Knockout:observableArray的自定义绑定,仅在完成时呈现

时间:2014-01-16 15:37:30

标签: javascript knockout.js ko.observablearray custom-binding

好的,标题可能有点令人困惑所以我会解释......

我正在编写一个自定义绑定,我将传递一个observableArray。这个observableArray是异步填充的,元素是逐个推送的。

问题是每次observableArray发生变异时都会调用我的自定义绑定(update方法)。这有意义,但在这个实例中没有用,因为它意味着第一个元素被渲染 n 次,其中 n 是observableArray的长度,第二个元素被渲染 n-1 次,只有 nth 元素被渲染一次。

任何人都可以解释一个简洁的方法,让自定义绑定只做任何事情

  • observableArray已完全填充,或
  • 何时添加了尚未由自定义绑定呈现的元素?

我可以想到几个方法,使用额外的属性/ observable作为父视图模型上的标志,表示“完全填充,您可以立即渲染项目”或每个元素上的属性说“你已经让我了”。但是,这些都很笨拙,特别是observableArray中的对象也有observableArray属性。

这个问题没有更好的Knockout / MVVM解决方案吗?

更新:为清楚起见,我正在构建的内容是这样的

<domElmnt data-bind="myBinding: { collection: TypeGroups }" />

,其中

TypeGroups = ko.observableArray();

并且TypeGroups中包含的元素都是具有可观察属性的另一个视图模型的所有实例。

每次调用TypeGroups.push(obj)时,都会再次调用自定义绑定。

3 个答案:

答案 0 :(得分:2)

无法准确判断是否有必要,但如果必须将customBinding放在observableArray上,我就会这样做。

您要做的是原子更新。方法splice就像通常的数组拼接一样。

yourArray.splice(atIndex, 0, elem1, elem2, elem3 ...)

但是这样并不是很有用:

yourArray.splice.apply(yourArray, [index, 0, elem1, elem2, elem3 ...])

这不是那么的,但我们可以做得更好。

function append(array, values) {
    var params = [array().length, 0];
    params.push.apply(params, values);
    array.splice.apply(array, params);
}

我很确定使用splice会自动附加所有元素而不会多次调用update。另一方面,调用array.push.apply(array, values)可能就足够了,不需要拼接。

但是!

如果我在你的位置,我会将obserableArray的绑定移动到observable数组中的项目。我不知道为什么你在更新后迭代你的所有项目。如果元素处理一次,是否有理由多次处理已处理的项目?如果没有,则自定义绑定可能不会在应有的位置使用。

在不了解您的问题的情况下,很难说出解决问题的最佳方法是什么。

答案 1 :(得分:0)

查看ko.utils.arrayPushAll()。

将所有对象转储到数组中并使用一个事务将它们全部推送出去。这将更新UI一次。

查看Ryan Niemeyer撰写的这篇文章 Utility Functions

答案 2 :(得分:0)

以下是我如何解决这个问题:每次调用自定义绑定时,我(安全地)计算已经将多少个孩子添加到上下文元素中:

var childCount = 0,
    children = element.childNodes,
    childMax = children.length;
for (var c = 0; c < childMax; c++) {
    if (children[c].nodeType != 3) {
        childCount++;
    }
}

然后,当我循环遍历指定的observableArray时,我使用childCount - 从 previous-element-count 开始 - 作为起始索引,并从该索引开始循环:< / p>

var coll = groupsCollection();    // groupsCollection is the specified observableArray
childMax = coll.length;
for (; childCount < childMax; childCount++) {
    // do something with coll[childCount ], such as using it to add a DOM node
}