【问题标题】:Notify that value changed in plain array通知在普通数组中更改的值
【发布时间】:2015-06-12 21:48:30
【问题描述】:

目前我绑定到普通数组。数组的值可以通过外部组件进行更改。

是否有可能发送值已更改的通知并重新渲染 DOM 树?

我不能使用 observables,因此valueHasMutated 不是解决方案,数组非常大,其中包含很多复杂的对象。

【问题讨论】:

  • 为什么不能使用 observables?
  • 因为没有schema,所以多租户应用中一切都是动态绑定的。
  • 如果您不知道架构,如何生成 HTML 模板?
  • XML 文档中描述的所有内容并构建在服务器端。然后它转换为 HTML 模板并在客户端绑定到 JSON。

标签: javascript knockout.js


【解决方案1】:

如果我理解正确,该数组是 ViewModel 的成员(您可以控制它),但您不能将其更改为 observableArray,因为您无法控制的东西会使用普通数组语法修改数组。此外,您可以在这些黑盒函数运行后采取一些措施,以通知模型数组可能已发生变异。

我们可以做到。定义一个(内部)observableArray 并在包装它的 ViewModel 上定义一个公共属性。这使您可以使用普通数组语法访问observableArray。但是,对数组的单个(非observable)元素的更改不会发送通知,因此您需要提供对内部observableArrayvalueHasMutated 方法的调用,以便在您进行更改时调用。

var vm = (function () {
    var arrayImpl = ['hi'];
    var obsArray = ko.observableArray(arrayImpl);
    var itemNumbers = [1,2,3,4,5,6,7,8,9];

    var self = {
        itemNumbers: itemNumbers,
        selectedItemNumber: ko.observable(1),
        newValue: ko.observable(),
        arrayHasMutated:obsArray.valueHasMutated
    };
    Object.defineProperty(self, 'plainArray', {
        get: obsArray,
        set: obsArray
    });
    return self;
});

ko.applyBindings(vm);

我们的应用可以像使用常规数组一样使用plainArray 属性。进行更新时,请致电arrayHasMutated

Item Number: <select data-bind="options:itemNumbers, value:selectedItemNumber"></select>
<br />
New Value: <input data-bind="value:newValue" />
<button data-bind="click:function () { var idx=selectedItemNumber()-1; plainArray[idx] = newValue(); arrayHasMutated(); }">Set it</button>
<ol data-bind="foreach:plainArray">
    <li data-bind="text:$data"></li>
</ol>
<br />
Length: <span data-bind="text:plainArray.length"></span>

试试看:http://jsfiddle.net/4jogh3k5/1/

【讨论】:

    【解决方案2】:

    如果您可以将另一个对象(而不是原始数组)传递给消费者,那么您可以使用defineProperty 来包装突变。

    var original = new Array(1, 2, 3, 4, 5, 6, 7, 8, 9, 0);
    var wrapper = {};
    for (var idx in original) {
        (function(prop) {
            Object.defineProperty(wrapper, prop, { 
                get: function() { return original[prop]; }, 
                set: function(v) { 
                    console.log("changing index " + prop + " to " + v);
                    original[prop] = v;
                }
            });
        })(idx);
    }
    

    显然,这仅在您更改索引处的值时才有效。如果您的数组有对象并且您直接更改其中一个对象,例如original[0].property = "value",那么您需要扩展此技术以访问数组中的每个对象并创建包装对象的等效结构。

    【讨论】:

    • 使用Object.defineProperty时,不要忘记同时设置configurable: true, enumerable: true,除非您希望它们为false,因为在这两种情况下它们的默认值都是false
    【解决方案3】:

    我假设您使用的是 Knockout.js,因为您已对其进行了标记。因此,您可以使用 ko.ObservableArray() 并将其绑定到 DOM。

    var originalArray = [1, 2, 3, 4];
    var observableArray = ko.ObservableArray(originalArray);
    

    this link

    【讨论】:

    • 第 2 行可以显着缩短您的代码:var watchedArray = ko.observableArray(originalArray ); 并删除整个 for-in-loop。另请注意,在 IE 8 for (index in array) 上,您必须 return;on 'index=='indexOf'`(这将是您的最后一个数组索引)。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-06-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-09-06
    相关资源
    最近更新 更多