web-dev-qa-db-fra.com

Détection des modifications apportées au modèle de vue Knockout

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

63
user1389723

Utilisez des extensions:

ko.extenders.trackChange = function (target, track) {
    if (track) {
        target.isDirty = ko.observable(false);
        target.originalValue = target();
        target.setOriginalValue = function(startingValue) {
            target.originalValue = startingValue; 
        };
        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 });

Vous pouvez maintenant inspecter comme ceci:

self.MyProperty.isDirty()

Vous pouvez également écrire une vue générique de ViewModel 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;
        }
    }
});

... puis vérifiez au niveau de viewModel

self.isDirty()
98
Brett Green

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 vous avertira lorsque personName change.

Ok, donc vous voulez 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)

49
web_bod

Pensez à utiliser plug-in Knockout-Validation

Il met en œuvre les éléments suivants:

yourProperty.isModified () - Vérifie si l'utilisateur a modifié la valeur.

yourProperty.originalValue - Vous pouvez donc vérifier si la valeur a vraiment changé.

Avec d'autres éléments de validation qui sont utiles!

À votre santé

5
dzl-pt

Vous pouvez utiliser le plugin ci-dessous pour cela:

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

Le code par exemple vous permettra de garder une trace de toutes les modifications dans n'importe quel viewModel:

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

PS: Pour l'instant, cela ne fonctionnera pas avec les abonnés imbriqués dans un tableau, mais une nouvelle version qui le prend en charge est en cours.

Mise à jour: L'exemple de code a été mis à niveau pour fonctionner avec la version 1.2b qui ajoute la prise en charge des éléments du tableau et des propriétés d'abonnement dans l'abonnement.

3
Ziad

J'ai adapté le code @Brett Green et l'ai étendu pour que nous puissions avoir AcceptChanges, marquant le modèle comme non sale et ayant une meilleure façon de marquer les modèles comme trackables. Voici le code:

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

ko.track(viewModel);

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

2
David Freire

J'ai eu le même problème, j'avais besoin d'observer tout changement sur le viewModel, afin de renvoyer les données au serveur, si quelqu'un est toujours intéressé, j'ai fait des recherches et c'est la meilleure solution que j'ai 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;
    };
};

pour utiliser cet "observateur global":

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 le rappel donné (dans ce cas 'Ajax_Submit') sera déclenché 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 retard pour envoyer 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 JavaScript et le framework knockout, (seulement hier j'ai commencé à travailler avec ce merveilleux framework), alors ne vous fâchez pas si je fais quelque chose de mal .. (-:

J'espère que cela t'aides!

2
Eitan H.S.

J'ai fait cela en prenant un instantané du modèle de vue lorsque la page se charge, puis en comparant plus tard cet instantané au modèle de vue actuel. Je me fichais de savoir quelles propriétés avaient changé, seulement si certaines avaient changé.

Prenez un instantané:

var originalViewModel = JSON.stringify(ko.toJS(viewModel));

Comparez plus tard:

if(originalViewModel != JSON.stringify(ko.toJS(viewModel))){
    // Something has changed, but we don't know what
}
1
Sgraffite

Considérons un modèle de vue comme suit

function myViewModel(){
    var that = this;
    that.Name = ko.observable();
    that.OldState = ko.observable();
    that.NewState = ko.observable();

    that.dirtyCalcultions - ko.computed(function(){
    // Code to execute when state of an observable changes.
});
}

Après avoir lié vos données, vous pouvez stocker l'état à l'aide de la fonction ko.toJS (myViewModel).

myViewModel.Name("test");
myViewModel.OldState(ko.toJS(myViewModel));

Vous pouvez déclarer une variable à l'intérieur de votre modèle de vue comme une observable calculée comme

that.dirtyCalculations = ko.computed(function () {});

Cette fonction calculée sera entrée en cas de modification de l'un des autres observables à l'intérieur du modèle de vue.

Ensuite, vous pouvez comparer les deux états du modèle de vue comme suit:

that.dirtyCalculations = ko.computed(function () {
  that.NewState(that);

  //Compare old state to new state
  if(that.OldState().Name == that.NewState().Name()){
       // View model states are same.
  }
  else{
      // View model states are different.
  }

});

** Remarque: cette fonction observable calculée est également exécutée la première fois lorsque le modèle de vue est initialisé. **

J'espère que cela t'aides ! À votre santé!!

1