Comment ignorer le chargement initial lorsque je regarde les modifications du modèle dans AngularJS?

J’ai une page Web qui sert d’éditeur pour une seule entité, qui se trouve sous la forme d’un graphe profond dans la propriété $ scope.fieldcontainer. Après avoir reçu une réponse de mon API REST (via la ressource $), j’ajoute une montre à ‘fieldcontainer’. J’utilise cette montre pour détecter si la page / l’entité est “sale”. En ce moment, je suis en train de faire rebondir le bouton de sauvegarde, mais je veux vraiment rendre le bouton de sauvegarde invisible jusqu’à ce que l’utilisateur vole le modèle.

Ce que j’obtiens, c’est un seul déclencheur de la montre, ce qui, je pense, se produit parce que l’affectation .fieldcontainer = … a lieu immédiatement après la création de ma montre. Je pensais juste à utiliser une propriété “dirtyCount” pour absorber la fausse alarme initiale mais cela semble très pirate … et j’ai pensé qu’il devait y avoir un moyen “angular idiomatique” pour gérer cela – je ne suis pas le seul utiliser une montre pour détecter un modèle sale.

Voici le code où j’ai mis ma montre:

$scope.fieldcontainer = Message.get({id: $scope.entityId }, function(message,headers) { $scope.$watch('fieldcontainer', function() { console.log("model is dirty."); if ($scope.visibility.saveButton) { $('#saveMessageButtonRow').effect("bounce", { times:5, direction: 'right' }, 300); } }, true); }); 

Je continue juste à penser qu’il doit y avoir une façon plus propre de faire cela que de garder mon code “UI salissant” avec un “if (dirtyCount> 0)” …

définir un drapeau juste avant le chargement initial,

 var initializing = true 

et puis quand le premier $ montre tire, faire

 $scope.$watch('fieldcontainer', function() { if (initializing) { $timeout(function() { initializing = false; }); } else { // do whatever you were going to do } }); 

Le drapeau sera supprimé à la fin du cycle de digestion en cours, le prochain changement ne sera donc pas bloqué.

La première fois que l’écouteur est appelé, l’ancienne valeur et la nouvelle valeur seront identiques. Alors faites ça:

 $scope.$watch('fieldcontainer', function(newValue, oldValue) { if (newValue !== oldValue) { // do whatever you were going to do } }); 

C’est en fait comme cela que les Angular Docs recommandent de le gérer :

Une fois qu’un observateur est enregistré avec la scope, le fn d’écoute est appelé de manière asynchrone (via $ evalAsync) pour initialiser l’observateur. Dans de rares cas, cela n’est pas souhaitable car le programme d’écoute est appelé lorsque le résultat de watchExpression n’a pas été modifié. Pour détecter ce scénario dans l’écouteur fn, vous pouvez comparer newVal et oldVal. Si ces deux valeurs sont identiques (===) alors l’écouteur a été appelé en raison de l’initialisation

Je me rends compte que cette question a été répondue, mais j’ai une suggestion:

 $scope.$watch('fieldcontainer', function (new_fieldcontainer, old_fieldcontainer) { if (typeof old_fieldcontainer === 'undefined') return; // Other code for handling changed object here. }); 

Utiliser des drapeaux fonctionne mais y a-t-il une odeur de code ?

Valide juste l’état du nouveau val:

 $scope.$watch('fieldcontainer',function(newVal) { if(angular.isDefined(newVal)){ //Do something } }); 

Lors du chargement initial des valeurs actuelles, l’ancien champ de valeur n’est pas défini. Ainsi, l’exemple ci-dessous vous aide à exclure les chargements initiaux.

 $scope.$watch('fieldcontainer', function(newValue, oldValue) { if (newValue && oldValue && newValue != oldValue) { // here what to do } }), true;