【问题标题】:ko observable array not triggering when last element removedko 可观察数组在删除最后一个元素时未触发
【发布时间】:2015-07-29 22:44:12
【问题描述】:

我有一个带有元素的地图,该元素显示当前正在加载哪些图层。我在一个可淘汰的可观察数组中保存了一个图层名称列表。加载新图层时,它们会按预期显示。当图层完成加载时,它们会按预期被移除,除了最后一个。即使调试显示它绑定的列表现在是空的,它也不会被删除。

初始化可观察对象:

self.currentlyLoadingLayers = ko.observableArray([]);

何时加载图层:

self.layerLoadingStarted(layerName);

图层加载时触发的事件:

layer.events.register('loadend', layer, function () {
    self.layerLoadingFinished(layerName);
});

以及被调用的函数:

self.layerLoadingStarted = function (layerName) {
    self.currentlyLoadingLayers.push(layerName);
};

self.layerLoadingFinished = function(layerName) {
    for (var i = self.currentlyLoadingLayers().length - 1; i >= 0; i--) {
        if (self.currentlyLoadingLayers()[i] === layerName) {
            self.currentlyLoadingLayers().splice(i, 1);
        }
    }
    //if (self.currentlyLoadingLayers().length === 0) self.currentlyLoadingLayers([]);
};

如果我取消注释上面函数中的最后一行,那么一切正常。为什么需要这个?不应该自动观察数组现在为空的事实吗?

我的绑定:

<div id="layersLoadingMessage" data-bind="visible: $root.currentlyLoadingLayers() && $root.currentlyLoadingLayers().length">
    <div data-bind="foreach: $root.currentlyLoadingLayers">
        <div data-bind="text: $data"></div>
    </div>
</div>

【问题讨论】:

  • 这是因为您正在操纵observableArray 的底层数组,绕过observableArray 对象上的淘汰订阅。

标签: javascript knockout.js


【解决方案1】:

observableArray 中的项目被添加或删除,或者整个集合被替换时,Knockout 将通知订阅者。但只有通过observableArray 对象而不是通过直接操作底层数组来完成。

所以这会通知订阅者:

self.currentlyLoadingLayers.splice(i, 1)

这不会:

self.currentlyLoadingLayers().splice(i, 1)

这将:

self.currentlyLoadingLayers([])

请查看observableArray 的文档。

我在您的代码中添加了一些 cmets 并进行了一些解释:

self.layerLoadingFinished = function(layerName) {
    for (var i = self.currentlyLoadingLayers().length - 1; i >= 0; i--) {
        if (self.currentlyLoadingLayers()[i] === layerName) {
            //this line modifies the underlying array directly bypassing ko's notifiers
            //change this to self.currentlyLoadingLayers.splice(i, 1)
            //to notify subscribers after each item is removed
            self.currentlyLoadingLayers().splice(i, 1);
        }
    }
    //this line uses self.currentlyLoadingLayers([]) which changes 
    //the underlying array through ko and will notify subscribers
    if (self.currentlyLoadingLayers().length === 0) self.currentlyLoadingLayers([]);
};

【讨论】:

  • 谢谢,现在更清楚了。刚接触 knockoutjs(我继承了该项目),我不理解 .splice().splice 之间的区别。我认为让我感到困惑的是来自.push 的通知正在清除以前使用().splice 删除的项目,使其看起来像().splice 正在通知订阅者。
  • @AndyNichols 没问题,哥们,很高兴我能帮上忙 :)
猜你喜欢
  • 2017-01-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-01-05
相关资源
最近更新 更多