64 votes

Détection du changement dans le modèle d'affichage masqué

Bien sûr, il est très facile de répondre à cette question, mais existe-t-il un moyen simple de déterminer si une propriété d'un modèle d'affichage masqué a changé?

98voto

Brett Green Points 521

Utiliser des rallonges:

 ko.extenders.trackChange = function (target, track) {
    if (track) {
        target.isDirty = ko.observable(false);
        target.originalValue = target();
        target.subscribe(function (newValue) {
            // use != not !== so numbers will equate naturally
            target.isDirty(newValue != target.originalValue);
        });
    }
    return target;
};
 

Ensuite:

 self.MyProperty= ko.observable("Property Value").extend({ trackChange: true });
 

Maintenant, vous pouvez inspecter comme ceci:

 self.MyProperty.isDirty()
 

Vous pouvez également écrire un viewModel générique parcourant pour voir si quelque chose a changé:

     self.isDirty = ko.computed(function () {
    for (key in self) {
        if (self.hasOwnProperty(key) && ko.isObservable(self[key]) && typeof self[key].isDirty === 'function' && self[key].isDirty()) {
            return true;
        }
    }
});
 

... et ensuite, vérifiez au niveau de viewModel

 self.isDirty()
 

50voto

web_bod Points 4055

Vous pouvez vous abonner aux propriétés que vous souhaitez surveiller:

 myViewModel.personName.subscribe(function(newValue) {
    alert("The person's new name is " + newValue); 
});
 

Cela alertera lorsque personName changera.

Ok, vous voulez donc savoir quand quelque chose change dans votre modèle ...

 var viewModel = … // define your viewModel

var changeLog = new Array();  

function catchChanges(property, value){
    changeLog.push({property: property, value: value});
    viewModel.isDirty = true;
}

function initialiseViewModel()
{
    // loop through all the properties in the model
    for (var property in viewModel) {

        if (viewModel.hasOwnProperty(property)) { 

            // if they're observable
            if(viewModel[property].subscribe){

                // subscribe to changes
                viewModel[property].subscribe(function(value) {
                    catchChanges(property, value);
                });
            }
        }
    }
    viewModel.isDirty = false;
}

function resetViewModel() {
    changeLog = new Array();  
    viewModel.isDirty = false;
}
 

(je ne l'ai pas testé - mais vous devriez avoir l'idée)

3voto

Ziad Points 460

Vous pouvez utiliser le plugin ci-dessous pour ceci:

https://github.com/ZiadJ/knockoutjs-reactor

Le code pour l'exemple vous permettra de garder une trace de tous les changements au sein de toute viewModel:

ko.watch(someViewModel, { depth: -1 }, function(parents, child) { 
    alert('New value is: ' + child());
});

PS: pour l'instant cela ne fonctionne pas avec subscribables imbriquée à l'intérieur d'un tableau, mais une nouvelle version qui prend en charge, il est sur le chemin.

Mise à jour: L'exemple de code a été mis à jour pour fonctionner avec v1.2b qui ajoute le support pour les éléments de tableau et subscribable-en-subscribable propriétés.

2voto

Eitan H.S. Points 74

J'ai eu le même problème, j'ai besoin d'observer tout changement dans le viewModel, afin d'envoyer les données au serveur, Si quelqu'un est toujours interessé, j'ai fait quelques recherches et c'est la meilleure solution iv e a réussi à assembler:

function GlobalObserver(viewModel, callback) {  
    var self = this;
    viewModel.allChangesObserver = ko.computed(function() {
        self.viewModelRaw = ko.mapping.toJS(viewModel);
    });
    viewModel.allChangesObserver.subscribe(function() {
        callback(self.viewModelRaw);
    });
    self.dispose = function() {
        if (viewModel.allChangesObserver)
            viewModel.allChangesObserver.dispose();
        delete viewModel.allChangesObserver;
    };
};

afin d'utiliser ce "global observateur":

function updateEntireViewModel() {
    var rawViewModel = Ajax_GetItemEntity(); //fetch the json object..    
    //enter validation code here, to ensure entity is correct.
    if (koGlobalObserver)
        koGlobalObserver.dispose(); //If already observing the older ViewModel, stop doing that!
    var viewModel = ko.mapping.fromJS(rawViewModel);        
    koGlobalObserver = new GlobalObserver(viewModel, Ajax_Submit);
    ko.applyBindings(viewModel [ ,optional dom element]);   
}

Notez que la fonction de rappel donnée (dans ce cas Ajax_Submit') sera tiré sur TOUT changement qui se produit sur le modèle de vue, donc je pense qu'il est vraiment recommandé de faire une sorte de mécanisme de délai pour envoyer de l'entité uniquement lorsque l'utilisateur a terminé de modifier les propriétés:

var _entitiesUpdateTimers = {};

function Ajax_Submit(entity) { 
    var key = entity.ID; //or whatever uniquely related to the current view model..
    if (typeof _entitiesUpdateTimers[key] !== 'undefined')
        clearTimeout(_entitiesUpdateTimers[key]);    
    _entitiesUpdateTimers[key] = 
        setTimeout(function() { SendEntityFunction(entity); }, 500);           
}

Je suis nouveau sur le JavaScript et le knock-out cadre, (uniquement yestarday j'ai commencé à travailler avec ce magnifique cadre), donc ne soyez pas en colère contre moi si j'ai fait quelque chose de mal.. (-:

Espérons que cette aide!

2voto

David Freire Points 76

J'ai adapté @Brett Green code et je l'ai étendu de manière à ce que nous puissions avoir AcceptChanges, marquant le modèle comme non sale, et disposant d'un moyen plus agréable de marquer les modèles comme étant traçables. Voici le code:

 var viewModel = {
    name: ko.observable()   
};

ko.track(viewModel);
 

http://jsfiddle.net/david_freire/3HZEu/2/

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X