【问题标题】:Is it possible to break out of a ko foreach binding before rendering is completed?是否有可能在渲染完成之前打破 ko foreach 绑定?
【发布时间】: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?特别是,&lt;pre data-bind="text: ko.toJSON($data, null, 2)"&gt;&lt;/pre&gt; 在可疑空值的绑定上下文中?
  • @MagnusAhlin 感谢您向我指出有关通用数组“foreach”引用的信息。不幸的是,由于我使用的是淘汰赛“foreach”,所以我不得不选择。
  • @alex 这是一个使用更智能调试的好建议。我只是在破解 ko 核心以在控制台中记录信息,但使用您指出的技巧似乎更容易!我会记住这些以供将来参考。

标签: knockout.js ko.observablearray durandal-2.0


【解决方案1】:

正如 Magnus Ahlin 指向How to short circuit Array.forEach like calling break? 的链接所指出的那样,似乎没有办法停止或突破 ko foreach 绑定,但是我的问题的根本原因实际上与我对虚拟元素的使用有关而不是普通的元素。

对于遇到淘汰赛问题并抱怨“Uncaught TypeError: Cannot read property 'insertBefore' of null”并使用虚拟元素通过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>

【讨论】:

  • 另外,组合涉及visible 或if 绑定的数据绑定也不是一个好主意。这些绑定应该独立于父绑定。事实上,在你断定问题出在虚拟绑定之前,请在我刚才给出的建议存在的情况下继续测试虚拟绑定。另外,除了解决您遇到的这个问题,您是否需要出于任何目的跳出foreach?
  • @EricTaylor 感谢您的反馈。我用更新的代码测试了我的情况,将 visible 绑定单独放在父 div 中,然后使用虚拟元素,但我遇到了同样的问题,所以虚拟元素似乎是我的问题的原因。不过,我将自行保留 visible 绑定,因此感谢您的建议。同样不,我想突破foreach 的唯一原因是解决在我的情况下由淘汰引发的错误,我在渲染之前从我的ko.observableArray 中删除项目。否则我不需要这样做。
  • 好的。很高兴知道。我在渲染表格时遇到了虚拟绑定的问题,但总能找到摆脱这种情况的方法。很高兴我能帮上忙。
猜你喜欢
  • 1970-01-01
  • 2018-04-21
  • 1970-01-01
  • 1970-01-01
  • 2020-02-25
  • 2018-09-19
  • 1970-01-01
  • 2019-12-31
  • 1970-01-01
相关资源
最近更新 更多