web-dev-qa-db-fra.com

Comment ignorer la charge initiale lorsque je regarde les modifications de modèles dans AngularJS?

J'ai une page Web qui sert d'éditeur pour une seule entité, qui se présente comme un graphe profond dans la propriété $ scope.fieldcontainer. Après avoir obtenu une réponse de mon API REST (via $ resource), j'ajoute une surveillance à 'fieldcontainer'. J'utilise cette montre pour détecter si la page/entité est "sale". Pour le moment, je fais rebondir le bouton de sauvegarde, mais je souhaite réellement le rendre invisible jusqu'à ce que l'utilisateur répugne au modèle.

Ce que je reçois, c’est un simple déclencheur de la montre, ce qui, je pense, est dû au fait que l’affectation .fieldcontainer = ... a lieu immédiatement après la création de ma montre. Je pensais simplement utiliser une propriété "dirtyCount" pour absorber la fausse alerte initiale, mais cela me semble très hacky ... et je me suis dit qu'il devait y avoir un "idiomatique angulaire" pour gérer cela - je ne suis pas le seul utiliser une montre pour détecter un modèle sale.

Voici le code où je mets 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 n'arrête pas de penser qu'il doit y avoir un moyen plus propre de faire cela que de garder mon code "salissant" avec un "if (dirtyCount> 0)" ...

181
Kevin Hoffman

mettre un drapeau juste avant le chargement initial,

var initializing = true

et puis quand le premier $ regarder des feux, faire

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

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

113
rewritten

La première fois que l’auditeur est appelé, l’ancienne valeur et la nouvelle valeur sont identiques. Alors faites ceci:

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

C’est ainsi que Angular docs recommande de le gérer :

Une fois qu'un observateur est enregistré avec l'étendue, le programme d'écoute fn 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 changé. Pour détecter ce scénario dans l'écouteur fn, vous pouvez comparer newVal et oldVal. Si ces deux valeurs sont identiques (===), le programme d'écoute a été appelé en raison de son initialisation.

472
MW.

Je me rends compte que cette question a reçu une réponse, 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.
});

L'utilisation de drapeaux fonctionne, mais a un peu de odeur de code à cela, vous ne pensez pas?

41
trixtur

Vient de valider l’état du nouveau val:

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

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

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