这是我关于SO的第一篇文章,所以请放轻松我:)
我正在使用Durandal.js构建一个Web应用程序,我有一种情况,我正在运行一个简单的淘汰foreach数据绑定,它迭代ko.observableArray并为数组中的每个项目组成子视图。这个数组由我想在页面上呈现的许多子视图/视图模型组成,但是数组一次可以包含大量项目(有时超过400)。该应用程序也可以有多个结果页面,我通过在单击新页面时替换ko.observableArray的内容来处理分页。
我偶尔遇到的问题(不是每次都有,但它是可重复的)是我收到了knockout.js(我正在运行的淘汰赛v3.0.0)抛出的错误,该错误说明如下:未捕获的TypeError:无法读取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代码片段中,containerNode.parentNode是#photosContainer,所以我觉得奇怪的是,因为foreach显然仍在运行,所以它是null(因为我为每个尚未渲染的项目抛出错误)。
以下是我的durandal应用程序的一些代码片段: 我视图中的html代码,其中包含foreach绑定,它遍历'photos'observableArray并组成子视图:
<div id='photosContainer' data-bind="visible: !video_mode_on(), foreach: photos">
<!-- ko compose: $data --><!--/ko-->
</div>
以下是我的viewmodel中的代码,它基本上替换了'photos'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()函数时直接推入它,但认为错误可能是由空数组引起的。我还尝试在#photosContainer上运行knockout的ko.virtualElements.emptyNode()函数,然后在我的getPhotos()函数中迭代rawPhotos()数组,看看是否会清空视图的foreach绑定中未完成的渲染,但是这似乎也没有做任何事情。我试图用一个check函数包装我的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;
}
};
到目前为止,没有任何工作,我的想法(和头发!!)已经用完了。任何帮助将不胜感激!
答案 0 :(得分:3)
似乎没有办法停止或突破ko foreach
绑定,正如Magnus Ahlin与How to short circuit Array.forEach like calling break?的链接所指出的那样,但我的问题的根本原因是实际上与我使用虚拟元素而不是普通元素有关。
对于任何遇到淘汰赛问题的人抱怨&#34; Uncaught TypeError:无法读取属性&#39; insertBefore&#39; of null&#34;并使用虚拟元素通过使用foreach
绑定在ko.observableArray中组合子视图,尝试用正常元素替换虚拟元素。
所以在视图中替换html代码,类似于:
<div data-bind="foreach: myObservableArray">
<!-- ko compose: $data --><!--/ko-->
</div>
有这样的事情:
<div data-bind="foreach: myObservableArray">
<div data-bind="compose: $data"></div>
</div>