【发布时间】:2015-02-15 03:07:26
【问题描述】:
这是我在 SO 上的第一篇文章,所以请放轻松 :)
我正在使用 Durandal.js 构建一个 Web 应用程序,并且我正在运行一个简单的淘汰赛 foreach 数据绑定,该数据绑定遍历 ko.observableArray 并为数组中的每个项目组成子视图。该数组由我想在页面上呈现的多个子视图/视图模型组成,但该数组一次可以包含大量项目(有时超过 400 个)。该应用程序还可以有多个结果页面,当单击新页面时,我通过替换 ko.observableArray 的内容来处理分页。
我偶尔遇到的问题(不是每次,但它是可重复的)是我收到了由 knockout.js 引发的错误(我正在运行 knockout v3.0.0),它说以下内容:“未捕获的类型错误:无法读取 null 的属性“insertBefore”。
这里是 knockout.js 的 virtualElements 的 prepend 方法中抛出错误的部分:
prepend: function(containerNode, nodeToPrepend) {
if (!isStartComment(containerNode)) {
if (containerNode.firstChild)
containerNode.insertBefore(nodeToPrepend, containerNode.firstChild);
else
containerNode.appendChild(nodeToPrepend);
} else {
// Start comments must always have a parent and at least one following sibling (the end comment)
containerNode.parentNode.insertBefore(nodeToPrepend, containerNode.nextSibling);
}
}
在挖空代码后,我可以看到被称为 null 的是 containerNode.parentNode。在我下面的 html 代码 sn-p 中,containerNode.parentNode 是 #photosContainer,所以我觉得奇怪的是它是 null,因为 foreach 显然仍在运行(因为我收到每个尚未运行的项目的错误尚未渲染)。
以下是我的 durandal 应用程序中的一些代码 sn-ps: 我的视图中的 html 代码,其中包含迭代“照片”observableArray 并组成子视图的 foreach 绑定:
<div id='photosContainer' data-bind="visible: !video_mode_on(), foreach: photos">
<!-- ko compose: $data --><!--/ko-->
</div>
这是来自我的视图模型的代码,它基本上替换了“照片”observableArray 的内容:
newHome.prototype.getPhotos = function() {
var self = this;
var defs = [];
var arr = [];
var args, newArr;
self.rawPhotos().forEach( function( set ) {
defs.push( self.some_more_all( set.mf, set.images ) );
});
$.when.apply($, defs).done(function( res ) {
args = Array.prototype.slice.call(arguments, 0);
newArr = args.sort();
newArr.forEach( function( set ) {
set.arr.forEach( function( p ) {
arr.push( self.addPhoto( p, self.mfOwnedByViewer( set.mf ) ? { ownedByViewer: true } : { ownedByViewer: false, owner_uuid: set.mf.owner_uuid } ) );
});
});
self.photos( arr );
});
};
当我在 foreach 绑定在我的视图中完成运行之前导航到另一个结果页面时,似乎会发生我提到的错误。所以我的问题是:有没有办法在我的视图中停止或中断 foreach 绑定,以便我可以导航到另一页结果而不必等待当前结果列表呈现?
还有一些我尝试过但没有帮助的事情:我最初是删除照片数组的所有内容,然后在运行我的 getPhotos() 函数时直接推入它,但认为错误可能是由空数组引起。在迭代我的 getPhotos() 函数中的 rawPhotos() 数组之前,我还尝试在 #photosContainer 上运行淘汰赛的 ko.virtualElements.emptyNode() 函数,以查看这是否会清空视图的 foreach 绑定中未完成的渲染,但是这似乎也没有做任何事情。我尝试使用检查函数来包装我的 compose 绑定,以查看 #photosContainer 节点是否存在,如下所示:
<div id='photosContainer' data-bind="visible: !video_mode_on(), foreach: photos">
<!-- ko if: $parent.checkForPhotosContainer() -->
<!-- ko compose: $data --><!--/ko-->
<!-- /ko -->
</div>
和检查功能:
newHome.prototype.checkForPhotosContainer = function() {
var self = this;
var el = $(self.element).find('#photosContainer');
if( el.length ) {
return true;
} else {
return false;
}
};
到目前为止,一切都没有奏效,而且我的想法(和头发!!)已经用完了。任何帮助将不胜感激!
【问题讨论】:
-
这看起来很难!您是否尝试过使用一些Knockout debugging tricks?特别是,
<pre data-bind="text: ko.toJSON($data, null, 2)"></pre>在可疑空值的绑定上下文中? -
@MagnusAhlin 感谢您向我指出有关通用数组“foreach”引用的信息。不幸的是,由于我使用的是淘汰赛“foreach”,所以我不得不选择。
-
@alex 这是一个使用更智能调试的好建议。我只是在破解 ko 核心以在控制台中记录信息,但使用您指出的技巧似乎更容易!我会记住这些以供将来参考。
标签: knockout.js ko.observablearray durandal-2.0