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

Posted

技术标签:

【中文标题】如何调试 KnockoutJS 的模板绑定错误?【英文标题】:How to debug template binding errors for KnockoutJS? 【发布时间】:2012-03-04 21:36:57 【问题描述】:

我一直在调试 KnockoutJS 模板中的问题。

假设我想绑定到一个名为“items”的属性,但在模板中我打错字并绑定到(不存在的)属性“item”。

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

"item" is not defined.

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

【问题讨论】:

【参考方案1】:

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

<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

【讨论】:

哦。我也需要问这个问题。使用复杂的代码来控制台记录数据。现在容易多了。 我必须更多地考虑调试技巧,并且可能会发表一篇博文。另一个想到的是手动订阅 observables 或计算 observables 以观察值的变化。就像name 是一个可观察到的行为name.subscribe(function(newValue) console.log("name", newValue); ); 可能是因为这个答案比较陈旧,但为什么不使用 console.log 并利用调试器的全部功能来查看对象属性呢?见即:***.com/a/16242988/647845 @DirkBoer - 使用 console.log 也是一个好方法。很多时候,我想在我的元素旁边看到数据,就像在foreach 场景中一样,但我发现在相关渲染标记中的页面上查看比在控制台中筛选更容易。只是视情况而定。我的更多想法在这里:knockmeout.net/2013/06/…。此外,您可能希望在绑定中记录一个“干净”版本,例如 console.log(ko.toJS(valueAccessor()) @RuneJeppesen - 我不确定您要序列化什么样的数据,但这样的事情可以提供帮助:knockmeout.net/2011/04/…【参考方案2】:

如果您使用 Chrome 进行开发,有一个名为 Knockoutjs context debugger 的非常棒的扩展程序(我不隶属于它),它直接在开发者工具的元素面板中向您显示绑定上下文。

【讨论】:

我希望 Firefox 或 Firebug 有这个。有人知道这样的事情吗? 似乎已放弃支持。如果您使用复杂的数据绑定结构,则会导致 chrome 崩溃。大约一年来我的任何项目都没有工作过。 很抱歉听到这个消息,虽然我早就从 KO 转到 Ember。 它(大部分)对我来说很好,而且我有一些非常复杂的结构。我还没有尝试过,但在它建议的扩展选项中,“如果您遇到崩溃,您可能有一个不可序列化的视图模型。您可以关闭序列化。”消息下方有一个复选框,用于禁用此功能。 非常有用,你。【参考方案3】:

在 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 调试器的全部功能,例如 在元素面板中显示 您不必将自定义元素添加到 DOM,仅用于调试

【讨论】:

【参考方案4】:

我找到了另一个有用的。我正在调试一些绑定并尝试使用 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>

【讨论】:

真的很有用。使用
 时遇到了淘汰循环和 Razor 标记问题。  是一个完美的解决方法。出于某种原因,像 @html.CheckBox 这样的 RAZOR 输入破坏了 ko.toJSON。
【参考方案5】:

Step by step guide

    对于本指南,我们将使用official KnockoutJS examples 之一。 说要查看第二个联系人背后的数据(Sensei 宫城)。 右键单击第二个联系人的第一个输入框(带有 文字“老师”)。 选择“检查元素”。 Chrome 开发者工具栏将打开。 打开 javascript 控制台窗口。您可以通过以下方式访问控制台 单击 Chrome 开发人员左下角的 &gt;= 图标 工具栏,或通过在 Chrome 开发人员中打开“控制台”选项卡 工具栏,或按 Ctrl+Shift+J 键入以下命令并按 Enter:ko.dataFor($0) 您现在应该看到绑定到第二行的数据。你可以 通过按对象左侧的小三角形来扩展数据 导航对象树。 键入以下命令并按 Enter:ko.contextFor($0) 您现在应该看到一个包含整个 淘汰赛上下文包括根和所有父母。这很有用 当您编写复杂的绑定表达式并且想要 尝试不同的结构。

这是什么黑魔法?

这个技巧是Chrome's $0-$4 feature 和KnockoutJS's utility methods 的组合。简而言之,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 的输出并直接从控制台操作视图模型。试试var root = ko.contextFor($0).$root; root.addContact(); 看看会发生什么:-)

调试愉快!

【讨论】:

【参考方案6】:

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

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> 

【讨论】:

【参考方案7】:

我创建了一个名为 knockthrough.js 的 github 项目来帮助可视化这些错误。

https://github.com/JonKragh/knockthrough

它突出显示绑定错误并提供该节点上数据上下文的转储。

你可以在这里玩一个示例:http://htmlpreview.github.io/?https://github.com/JonKragh/knockthrough/blob/master/default.htm

感谢 RP Niemeyer,他在 SO 上出色的 Knockout 代码示例让我走到了这一步。

【讨论】:

【参考方案8】:

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

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

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

【讨论】:

【参考方案9】:

所有其他答案都很好,我只是添加我喜欢做的事情:

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

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

淘汰码:

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

这将暂停调试器中的代码,elementvalueAccessor() 将包含有价值的信息。

【讨论】:

不需要自定义绑定。看看***.com/documentation/knockout.js/5066/… 是的,我同意没有必要这样做,我只是想指出这是一种调试方式......每个人似乎都喜欢以自己的方式这样做:)【参考方案10】:

如果你在 Visual Studio 和 IE 中开发,我更喜欢 data-bind="somebinding:(function()debugger; return bindvalue; )()" 我更喜欢 echo 函数,因为它会转到带有所有绑定的脚本而不是 eval 文件,你可以只看 $上下文 $data(我也在 Chrome 中使用它);

【讨论】:

我敢打赌这与 Visual Studio 或 IE 无关。 @Serhiy 与 chrome 相同,但在 chrome 中我认为您可以在没有它的情况下访问该文件我认为您无法在 VS 中访问该文件。【参考方案11】:

这对我有用:

<div data-bind="text: function() debugger; ()"></div>

【讨论】:

【参考方案12】:

如果您在 Magento2 项目中使用 KnockoutJS,您可以使用 Magento 的自定义 afterRender 绑定:

<div afterRender="function (target, viewModel) 
    console.log('Rendered element:', target);
    console.log('Associated view model:', viewModel);
    console.log(this === viewModel);
"></div> 

【讨论】:

【参考方案13】:

此答案基于 Dirk Boer 的答案。我添加到他的处理程序,以便它在更新时也显示数据:

ko.bindingHandlers.debug = 

    init: function(element, valueAccessor) 
    
        console.log( 'Knockoutbinding (init):', element, ko.toJS(valueAccessor()));
    ,
    update: function(element, valueAccessor)
    
        console.log( 'Knockoutbinding (update):', element, ko.toJS(valueAccessor()));
    
;

然后,您所要做的就是在您的 HTML 代码中添加这样的绑定:

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

当console.log初始化或更新时,你会在它看到数据。

【讨论】:

以上是关于如何调试 KnockoutJS 的模板绑定错误?的主要内容,如果未能解决你的问题,请参考以下文章

KnockoutJS基础知识

在模板中使用时,knockoutjs if 和 ifnot 绑定无法正常工作

如何结合 KnockoutJS 使用 HTML5 拖放?

KnockoutJS 3.X API 第四章 数据绑定 控制流component绑定

如何将focusOut事件绑定到knockoutjs

如何使用KnockoutJS数据绑定iframe的内容?