Knockout订阅可观察复杂对象的任何更改

chr*_*tor 27 knockout.js

我有一个viewmodel,它包含一个observable,用对象初始化.这个对象本身包含了observables.

我的目标是在对象发生变化时通知(或者:当该对象中的任何可观察变化时)

的jsfiddle

复杂对象:

var ns = ns || {};

ns.ComplexObj = function (item) {
    var self = this;

    if (!item) {
        item = {};
    }

    self.id = item.Id || '';
    self.company = ko.observable(item.Company || '');
    self.email = ko.observable(item.Email || '');

    self.company.subscribe(function () {
       console.log('debug: company changed');
    });

    return self;
};
Run Code Online (Sandbox Code Playgroud)

视图模型

ns.mainvm = function () {
   var simpleObject = ko.observable('i am pretty simple');

   simpleObject.subscribe(function (newValue) {
       document.getElementById('simpleSubscribtionFeedback').innerText = newValue;
   });

   var complexObject = ko.observable(ns.ComplexObj());
   complexObject.subscribe(function (newValue) {
       // i would like to react to any change in complex object
       document.getElementById('complexSubscribtionFeedback').innerText = 'i dont get executed :(';
   });

   return {
       simpleObject: simpleObject,
       complexObject: complexObject
   };
};
Run Code Online (Sandbox Code Playgroud)

捆绑

var container = document.getElementById('wrapper');
if (container) {
   ko.applyBindings(ns.mainvm, container);
} else {
   console.warn("container for binding ko not found");
}
Run Code Online (Sandbox Code Playgroud)

有没有可能对复杂对象的变化做出反应?任何帮助表示赞赏.

我已经尝试过rpniemeyer中的dirtyFlag解决方案(评论中的链接).复杂对象上的脏标志的问题是,当它切换到"true"并且我挂钩到该标志的订阅时,那只是第一次就可以了.为了对进一步的更改作出反应,我需要再次将dirtyFlag设置为false(在订阅后执行我的操作).这将导致订阅循环.

sro*_*oes 48

您可以使用以下技巧:

ko.computed(function() {
    return ko.toJSON(complexObject);
}).subscribe(function() {
    // called whenever any of the properties of complexObject changes
});
Run Code Online (Sandbox Code Playgroud)

http://jsfiddle.net/xcajt4qn/3/

这样做的原因是ko.toJSON递归读取对象中的所有属性,因此使得计算依赖于所有属性.

  • 你很生气找到这个伎俩.但也很棒. (7认同)
  • 请注意,只要任何对象的*non*-observable属性发生更改,也会调用此方法,这可能不是所希望的. (4认同)
  • @tloflin怎么样?这些属性不会有任何跟踪变化 (2认同)
  • 提示:在订阅中放入console.log以检查它是否被调用了太多次.您可以使用速率限制observable来避免过多的事件,如果字段是文本输入,这些事件尤其有用.在该情况的`subscribe`函数之前添加`extend({rateLimit:500})`.我相信`rateLimit:0`或`extend({deferred:true});`如果您发现每个更改都会收到多个事件,那么它可能很有用. (2认同)