web-dev-qa-db-fra.com

Abonnez-vous à tout changement d'objet complexe observable

J'ai un viewmodel qui contient un observable, qui est initialisé avec un objet. cet objet lui-même contient des observables.

mon objectif est d'être averti chaque fois que cet objet change (ou: quand tout observable dans cet objet change)

jsfiddle

objet complexe :

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;
};

viewmodel

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
   };
};

liaison

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

est-il possible de réagir aux changements sur un objet complexe? toute aide est appréciée.

j'ai déjà essayé les solutions dirtyFlag (lien dans les commentaires), de rpniemeyer. le problème avec un drapeau sale sur l'objet complexe est que, quand il passe à "vrai" et que je me connecte à l'abonnement de ce drapeau, ce n'est ok que pour la première fois. pour réagir à de nouveaux changements, je devrais redéfinir le dirtyFlag sur false (après avoir fait mes affaires dans l'abonnement). ce qui conduirait à une boucle d'abonnement.

26
chris vietor

Vous pouvez utiliser l'astuce suivante:

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

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

La raison pour laquelle cela fonctionne est ko.toJSON lira récursivement toutes les propriétés de l'objet, ce qui rendra le calcul dépendant de toutes les propriétés.

46
sroes