【问题标题】:Knockout's mapping breaks observable arraysKnockout 的映射破坏了可观察的数组
【发布时间】:2012-02-20 13:59:00
【问题描述】:

我在使用 Knockout 的映射插件时遇到了一个奇怪的问题。

如果我通过映射填充可观察数组,我无法迭代数组或获取其长度,即使 UI 已正确更新,数组似乎也是空的。

你可以在这里找到一个工作的 jsFiddle:http://jsfiddle.net/VsbsC/

这是 HTML 标记:

<p><input data-bind="click: load" type="button" value="Load" /></p>
<p><input data-bind="click: check" type="button" value="Check" /></p>
<table>
    <tbody data-bind="foreach: items">
        <tr>
            <td data-bind="text: name"></td>
            <td data-bind="text: value"></td>
        </tr>
    </tbody>
</table>
<p data-bind="text: total"></p>

这是 JavaScript 代码:

var ViewModel = function () {
    var self = this;
    self.items = ko.observableArray();
    self.load = function () {
        self.items([
            { "name": "joey", "value": 1 },
            { "name": "anne", "value": 2 },
            { "name": "paul", "value": 3 },
            { "name": "mike", "value": 4 }
        ]);
    };
    self.check = function () {
        alert(self.items().length);
    };
    self.total = ko.computed(function () {
        var total = 0;
        for (var i = 0; i < self.items().length; i++) {
            total += self.items()[i].value;
        }
        return total;
    });
};
var viewModel = new ViewModel();
ko.applyBindings(viewModel);

当我点击 Load 按钮时,记录和总数都正确显示,当我点击 Check 按钮时,我得到正确的项目编号。

但是,如果我改变了

self.items([
    { "name": "joey", "value": 1 },
    { "name": "anne", "value": 2 },
    { "name": "paul", "value": 3 },
    { "name": "mike", "value": 4 }
]);

self.items(ko.mapping.fromJS([
    { "name": "joey", "value": 1 },
    { "name": "anne", "value": 2 },
    { "name": "paul", "value": 3 },
    { "name": "mike", "value": 4 }
]));

UI 仍然可以正确呈现,但总数显示为零,单击 Check 也会产生零,console.info-ing self.items 产生一个空数组。

这怎么可能?教程重读了无数遍,搞不懂自己做错了什么。

附:我需要通过映射插件填充可观察数组,因为在实际页面中,值来自 AJAX 请求。

【问题讨论】:

    标签: knockout.js observer-pattern knockout-mapping-plugin


    【解决方案1】:

    您看到的问题是基于这样一个事实,即如果给定一个数组,映射插件将创建一个 observableArray。因此,您将 self.items observableArray 的值设置为等于 observableArray(而不仅仅是一个数组)。所以,它被包裹了一个额外的时间。

    这是一种方法:

    var ViewModel = function () {
        var self = this;
        self.items = ko.mapping.fromJS([]);
        self.load = function () {
            ko.mapping.fromJS([
                { "name": "joey", "value": 1 },
                { "name": "anne", "value": 2 },
                { "name": "paul", "value": 3 },
                { "name": "mike", "value": 4 }
            ], self.items);
        };
        self.check = function () {
            alert(self.items().length);
        };
        self.total = ko.computed(function () {
            var total = 0, items = self.items();
            for (var i = 0; i < items.length; i++) {
                total += items[i].value();
            }
            return total;
        });
    };
    var viewModel = new ViewModel();
    ko.applyBindings(viewModel);
    

    因此,您使用映射插件初始化原始 observableArray,因此它已准备好进行更新。然后,在更新时调用 ko.mapping.fromJS 并使用更新的数据和要更新的映射对象。

    当时的另一个小改动是在计算的 observable 中使用 value(),因为它是映射插件的 observable。

    示例:http://jsfiddle.net/rniemeyer/3La5K/

    【讨论】:

    • 您的代码完美运行。问题出在self.items = ko.mapping.fromJS([]);:在问题之前的测试中,我确实尝试了你写的东西,但是我用self.items = ko.observableArray(); 初始化了属性,但它不起作用。由于在mapping's documentation 中找不到任何内容,我打开a ticket 请求添加解释。
    • 是的,你的 UI 已经绑定到原始 observableArray,所以当你用你的数据更新它时,你要确保你能够更新原始数组而不是用新数组替换它.
    【解决方案2】:

    您需要将 items observableArray 传递给映射函数,以便它可以将新值映射到其中。

    这里的工作解决方案: http://jsfiddle.net/unklefolk/j9pdX/

    self.load = function () {
        ko.mapping.fromJS([
            { "name": "joey", "value": 1 },
            { "name": "anne", "value": 2 },
            { "name": "paul", "value": 3 },
            { "name": "mike", "value": 4 }
        ], {}, self.items);
    };
    

    【讨论】:

      【解决方案3】:

      或者你可以试试knockout-data-projections

      它可以很好地处理视图模型到 js 数组的映射!!

      【讨论】:

        猜你喜欢
        • 2017-06-20
        • 2018-07-25
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-12-03
        • 1970-01-01
        • 2012-10-14
        • 1970-01-01
        相关资源
        最近更新 更多