在Knockout中扩充数组项上下文

时间:2013-11-14 17:06:50

标签: javascript knockout.js foreach

目前,使用Knockout foreach绑定时,您可以使用$index访问当前索引。我想为我的内部绑定提供其他类似的功能 - 例如:

  • array(让我访问正在操作的阵列)
  • length(所述阵列的长度)
  • first(当前项目是否为第一项)
  • last(当前项目是否为最后一项)
  • only(当前项目是否为唯一项目)

你明白了。不幸的是,设置$index的代码深埋在template绑定的代码中,没有明显的方法来增强上下文。

我可以通过扩展array的自定义length绑定来访问foreachbindingContext(我知道有关此问题的警告:{{ 1}}但它适用于我),但我无法弄清楚如何实现需要访问“当前”项的其他方法,而没有为每个数组迭代执行的自定义内部绑定。

我希望能够做到这样的事情:

destroy

(据我们所知,<div data-bind="foreach: items"> <input type="text" data-bind="value: description" /> <button data-bind="visible: $last, click: $array.push({})">Add Another</button> </div> $array都不存在。假设$last元素可能来自外部模板而无法知道如何路径到当前数组(因此button对我来说不起作用)。

有办法做到这一点吗?

2 个答案:

答案 0 :(得分:1)

我能想到的最好的方法是创建专门的绑定来存储有关数组和当前项的上下文信息。

自定义foreach绑定,公开有关数组的上下文:

ko.bindingHandlers.xforeach = (function() {
    var createContext = function(array) {
        return {
            '$array': array,
            '$arrayLength': function() { return ko.unwrap(array).length; }
        };
    };
    return {
        init: ko.bindingHandlers.foreach.init,
        update: function(element, valueAccessor, allBindings, viewModel, bindingContext) {
            var extendedContext = createContext(valueAccessor());
            return ko.bindingHandlers.foreach.update.call(this, element, valueAccessor, allBindings, viewModel, bindingContext.extend({
                '$foreachContext' : extendedContext
            }));
        }    
    };
})();
ko.virtualElements.allowedBindings.xforeach = true;

自定义template绑定,公开有关项/数组的上下文:

ko.bindingHandlers.xforeachItem = (function() {
    var createContext = function(currentContext, forEachContext) {
        return {
            first: function() { return currentContext.$index() === 0; },
            last: function() { return currentContext.$index() === (forEachContext.$arrayLength() - 1); }
        };
    };
    return {
        init: ko.bindingHandlers.template.init,
        update: function(element, valueAccessor, allBindings, viewModel, bindingContext) {
            var extendedContext = createContext(bindingContext, bindingContext.$parentContext.$foreachContext);
            return ko.bindingHandlers.template.update.call(this, element, valueAccessor, allBindings, viewModel, bindingContext.extend({
                '$foreachItemContext' : extendedContext
            }));
        }
    };
})();
ko.virtualElements.allowedBindings.xforeachItem = true;

使用示例:

<div data-bind="xforeach: items">
    <div data-bind="xforeachItem: {}">
        <input type="text" data-bind="value: description" />        
        <span data-bind="visible: $foreachItemContext.first(), text: $foreachContext.$arrayLength()"></span>
        <button data-bind="visible: $foreachItemContext.last(), click: $root.add">Add Another</button>
    </div>
</div>

最后,一个小提琴显示它在行动:http://jsfiddle.net/magnafides/wkCLd/2/

答案 1 :(得分:0)

您可以使用$ parent.data()来获取实际数组。

对于 $length ,您可以这样做:

$parent.items.length

对于 $first ,您可以这样做:

$index() == 0

对于 $last ,您可以这样做:

$index() == ($parent.items.length - 1)

对于 $only ,您可以这样做:

$index() == 0 && $parent.items.length == 1

这是fiddle