如何调试KnockoutJS的模板绑定错误?


199

我一直在调试KnockoutJS模板中的问题时遇到麻烦。

假设我想绑定到名为“ items” 的属性,但是在模板中输入错误并绑定到(不存在的)属性“ item”。

使用Chrome调试器只会告诉我:

"item" is not defined.

是否有工具,技术或编码风格可以帮助我获得有关绑定问题的更多信息?

Answers:


344

当在某个范围内可用的数据存在问题时,我经常做的一件事是将模板/部分替换为以下内容:

<div data-bind="text: ko.toJSON($data)"></div>

或者,如果您想要一个更具可读性的版本:

<pre data-bind="text: JSON.stringify(ko.toJS($data), null, 2)"></pre>

这将吐出在该范围内绑定的数据,并确保您适当地嵌套事物。

更新:从KO 2.1开始,您可以将其简化为:

<pre data-bind="text: ko.toJSON($data, null, 2)"></pre>

现在,参数传递给JSON.stringify


哦 我也需要问这个问题。使用复杂的代码段来console.log数据。现在要容易得多。
AlfeG 2012年

3
我必须考虑更多有关调试技​​巧的信息,也许还要撰写博客文章。我想到的另一个是对可观察值或计算的可观察值进行手动订阅以观察值的变化。好像name是可以观察到的那样name.subscribe(function(newValue) { console.log("name", newValue); });
RP Niemeyer 2012年

1
可能是因为此答案相对较旧,但是为什么不使用console.log并利用调试器的全部功能查看对象属性呢?参见ie stackoverflow.com/a/16242988/647845
Dirk Boer

1
@DirkBoer-使用console.log也是一个很好的方法。很多时候,我希望像在foreach场景中一样,在元素旁边查看数据,而且与在控制台中进行筛选相比,我发现在页面上查看相关渲染标记更容易。只是视情况而定。我在这里的其他想法:kickmeout.net/2013/06/…。另外,您可能希望在绑定中记录“干净”版本,例如console.log(ko.toJS(valueAccessor())
RP Niemeyer 2014年

1
@RuneJeppesen-我不确定您要序列化什么样的数据,但类似的方法可以帮助您:kickmeout.net/2011/04/…–
RP Niemeyer

61

如果您使用Chrome进行开发,则有一个非常不错的扩展(我不隶属于),称为Knockoutjs上下文调试器,可以直接在“开发人员工具”的“元素”面板中显示绑定上下文。


3
我希望Firefox或Firebug拥有此功能。有人知道这样的事吗?
Patrick Szalapski 2014年

似乎支持已被删除。如果您使用复杂的数据绑定结构,则会导致Chrome崩溃。大约一年来我的任何项目都没有工作。
北极

很抱歉听到这个消息,尽管我已经从KO转到Ember很久了。
neverfox 2015年

1
(对我来说)(大部分)工作正常,并且我有一些非常复杂的结构。我还没有尝试过,但是在扩展的选项中它建议:“如果遇到崩溃,您可能拥有不可序列化的视图模型。您可以关闭序列化。” 消息下方有一个复选框,用于禁用此功能。
格林2015年

ty,非常有用。
安德鲁(Andrew)

37

在JavaScript库文件中的某处定义一次bindingHandler

ko.bindingHandlers.debug = 
{
    init: function(element, valueAccessor) 
    {
        console.log( 'Knockoutbinding:' );
        console.log( element );
        console.log( ko.toJS(valueAccessor()) );
    }
};

而不是像这样简单地使用它:

<ul data-bind="debug: $data">

优点

  • 使用Chrome调试器的全部功能,例如Elements面板中的Reveal
  • 您不必将自定义元素添加到DOM中,仅用于调试

在此处输入图片说明


32

我发现了另一个可能有用的东西。我正在调试一些绑定,并尝试使用Ryans示例。我收到一个错误,发现JSON找到了一个循环。

<ul class="list list-fix" data-bind="foreach: detailsView().tabs">
 <li>
   <pre data-bind="text: JSON.stringify(ko.toJS($parent), null, 2)"></pre>
   <a href="#" data-bind="click: $parent.setActiveTab, text: title"></a>
 </li>
</ul>

但是,使用这种方法将数据绑定值替换为以下内容:

  <ul class="list list-fix" data-bind="foreach: detailsView().tabs">
    <li>
      <pre data-bind="text: 'click me', click: function() {debugger}"></pre>
      <a href="#" data-bind="click: $parent.setActiveTab, text: title"></a>
    </li>
  </ul>

现在,如果在打开chrome调试窗口的同时单击PRE元素,则会得到一个填充良好的范围变量窗口。

找到了更好的方法:

<pre data-bind="text: ko.computed(function() { debugger; })"></pre>

真的很有用。使用<pre data-bind =“ text:ko.toJSON($ data,null,2)”> </ pre>遇到敲除循环循环和Razor标记问题。<pre ... debugger>是一个完美的解决方法。由于某种原因,像@ Html.CheckBox这样的RAZOR输入打破了ko.toJSON。
2014年

20

逐步指南

  1. 对于本指南,我们将使用官方的KnockoutJS示例之一
  2. 假设您要查看第二个联系人(Sensei Miyagi)背后的数据。
  3. 右键单击第二个联系人的第一个输入框(带有文本“ Sensei”的那个)。
  4. 选择“检查元素”。Chrome开发者工具栏将打开。
  5. 打开JavaScript控制台窗口。您可以通过以下方式访问控制台:单击>=Chrome开发者工具栏左下方的图标,或打开Chrome开发者工具栏的“控制台”标签,或按Ctrl+ Shift+J
  6. 输入以下命令,然后按Enter: ko.dataFor($0)
  7. 现在,您应该看到绑定到第二行的数据。您可以通过按对象左侧的小三角形来展开数据,以浏览对象树。
  8. 输入以下命令,然后按Enter: ko.contextFor($0)
  9. 现在,您应该看到一个复杂的对象,其中包含整个Knockout上下文,包括根和所有父级。当您编写复杂的绑定表达式并且要尝试不同的构造时,这很有用。

遵循上述指南时的示例输出

这是什么黑魔法?

这个技巧是Chrome的$ 0- $ 4功能KnockoutJS的实用程序方法的结合。总之,Chrome会记住您在Chrome开发者工具栏选择哪些元素和别名下公开这些元素$0$1$2$3$4。因此,当您在浏览器中右键单击某个元素并选择“检查元素”时,该元素会自动在别名下变为可用$0。您可以将此技巧与KnockoutJS,AngularJS,jQuery或任何其他JavaScript框架一起使用。

技巧的另一面是KnockoutJS的实用程序方法ko.dataFor和ko.contextFor:

  • ko.dataFor(element) -返回可用于与元素绑定的数据
  • ko.contextFor(element) -返回DOM元素可用的整个绑定上下文。

请记住,Chrome的JavaScript控制台是功能齐全的JavaScript运行时环境。这意味着您不仅限于查看变量。您可以ko.contextFor直接从控制台存储和操作viewmodel 的输出。尝试var root = ko.contextFor($0).$root; root.addContact();看看会发生什么:-)

调试愉快!


7

看看我使用的一个非常简单的东西:

function echo(whatever) { debugger; return whatever; }

要么

function echo(whatever) { console.log(whatever); return whatever; }

然后在html中说:

<div data-bind="text: value"></div>

只需将其替换为

<div data-bind="text: echo(value)"></div>

更先进:

function echo(vars, member) { console.log(vars); debugger; return vars[0][member]; }

<div data-bind="text: echo([$data, $root, $parents, $parentContext], 'value')"></div>

请享用 :)

更新

另一个烦人的事情是,当您尝试绑定到未定义的值时。假设在上面的示例中,数据对象只是{}而不是{value:'some text'}。在这种情况下,您会遇到麻烦,但是通过以下调整,您会没事的:

<div data-bind="text: $data['value']"></div> 


3

查看要传递给绑定的数据的最简单方法是将数据拖放到控制台:

<div data-bind="text: console.log($data)"></div>

淘汰赛将评估文本绑定的值(实际上可以在此处使用任何绑定),并将$ data刷新到控制台浏览器面板。


2

所有其他答案将非常有用,我只是添加我想做的事情:

在您的视图中(假设您已经绑定了一个ViewModel):

<div data-bind="debugger: $data"></div>

淘汰代码:

ko.bindingHandlers.debugger = {
    init: function (element, valueAccessor) {
        debugger;
    }
}

这将暂停在调试器的代码,element并且valueAccessor()将包含有价值的信息。



1
是的,我同意没有必要以这种方式进行操作,我只想指出这是一种调试方式...每个人似乎都喜欢以自己的方式进行操作:)
Aditya MP

1

如果您是在Visual Studio和IE中进行开发,我会更data-bind="somebinding:(function(){debugger; return bindvalue; })()"喜欢它,然后是echo函数,因为它会转到包含所有绑定的脚本中,而不是eval文件,您可以看一下$ context $ data(我使用在Chrome中也是如此);


我敢打赌它与Visual Studio或IE无关。
谢里(Serhiy)

@Serhiy与chrome相同,但在chrome中,我认为您可以在没有它的情况下访问文件,我认为您无法在VS中访问文件。
Filip Cordas's

0

这对我有用:

<div data-bind="text: function(){ debugger; }()"></div>
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.