Question Comment utiliser $ scope. $ Watch et $ scope. $ S'appliquent dans AngularJS?


Je ne comprends pas comment utiliser $scope.$watch et $scope.$apply. La documentation officielle n'est pas utile.

Ce que je ne comprends pas spécifiquement:

  • Sont-ils connectés au DOM?
  • Comment puis-je mettre à jour les modifications DOM dans le modèle?
  • Quel est le point de connexion entre eux?

j'ai essayé ce tutoriel, mais il faut la compréhension de $watch et $apply pour acquis.

Qu'est-ce que $apply et $watch faire, et comment puis-je les utiliser de manière appropriée?


1007
2018-02-27 12:50


origine


Réponses:


Vous devez être conscient de la façon dont AngularJS fonctionne pour le comprendre.

Cycle de résumé et $ scope

AngularJS définit avant tout un concept de soi-disant cycle de digestion. Ce cycle peut être considéré comme une boucle, au cours de laquelle AngularJS vérifie s'il y a des changements à toutes les variables regardé par tous les $scopes. Donc si vous avez $scope.myVar défini dans votre contrôleur et cette variable était marqué pour être regardé, alors vous dites implicitement à AngularJS de surveiller les changements sur myVar dans chaque itération de la boucle.

Une question de suivi naturelle serait: est-ce que tout est attaché à $scope être regardé? Heureusement, non. Si vous souhaitez surveiller les modifications apportées à chaque objet de votre $scope, alors rapidement une boucle digérer prendrait des années à évaluer et vous seriez rapidement confronté à des problèmes de performance. C'est pourquoi l'équipe AngularJS nous a donné deux façons de déclarer $scope variable comme étant regardé (lire ci-dessous).

$ watch aide à écouter les changements de portée de $

Il y a deux façons de déclarer $scope variable comme étant regardé.

  1. En l'utilisant dans votre template via l'expression <span>{{myVar}}</span>
  2. En l'ajoutant manuellement via le $watch un service

Annonce 1) C'est le scénario le plus courant et je suis sûr que vous l'avez déjà vu, mais vous ne saviez pas que cela a créé une montre en arrière-plan. Oui, ça l'avait! En utilisant les directives AngularJS (telles que ng-repeat) peut également créer des montres implicites.

Annonce 2) C'est comme ça que vous créez votre propre montres. $watch service vous aide à exécuter du code lorsque la valeur attachée à la $scope a changé. Il est rarement utilisé, mais parfois utile. Par exemple, si vous voulez exécuter du code chaque fois que 'myVar' change, vous pouvez faire ce qui suit:

function MyController($scope) {

    $scope.myVar = 1;

    $scope.$watch('myVar', function() {
        alert('hey, myVar has changed!');
    });

    $scope.buttonClicked = function() {
        $scope.myVar = 2; // This will trigger $watch expression to kick in
    };
}

$ apply permet d'intégrer les modifications avec le cycle de digestion

Vous pouvez penser à la $apply fonctionner comme un mécanisme d'intégration. Vous voyez, chaque fois que vous changez certains variable regardée attachée à la $scope objet directement, AngularJS saura que le changement est arrivé. C'est parce qu'AngularJS savait déjà surveiller ces changements. Donc, si cela se passe dans du code géré par le framework, le cycle de digestion se poursuivra.

Cependant, parfois vous voulez changer une valeur en dehors du monde AngularJS et voir les changements se propager normalement. Considérez ceci - vous avez un $scope.myVar valeur qui sera modifiée dans un jQuery $.ajax()gestionnaire. Cela arrivera à un moment donné dans le futur. AngularJS ne peut pas attendre que cela se produise, car il n'a pas été invité à attendre sur jQuery.

Pour y remédier, $apply a été introduit. Il vous permet de démarrer le cycle de digestion explicitement. Cependant, vous ne devriez utiliser ceci que pour migrer certaines données vers AngularJS (intégration avec d'autres frameworks), mais n'utilisez jamais cette méthode combinée avec un code AngularJS normal, car AngularJS va alors lancer une erreur.

Comment tout cela est-il lié au DOM?

Eh bien, vous devriez vraiment suivre le tutoriel, maintenant que vous savez tout cela. Le cycle de digest veillera à ce que l'interface utilisateur et le code JavaScript restent synchronisés, en évaluant chaque observateur attaché à tous $scopes tant que rien ne change. Si plus aucun changement ne se produit dans la boucle de résumé, alors il est considéré comme terminé.

Vous pouvez attacher des objets à $scope objet soit explicitement dans le contrôleur, ou en les déclarant dans {{expression}} former directement dans la vue.

J'espère que cela aide à clarifier certaines connaissances de base sur tout cela.

Autres lectures


1648
2018-02-27 13:14



Dans AngularJS, nous mettons à jour nos modèles, et nos vues / templates mettent à jour le DOM "automatiquement" (via des directives intégrées ou personnalisées).

$ apply et $ watch, les deux étant des méthodes Scope, ne sont pas liés au DOM.

le Concepts page (section "Runtime") a une très bonne explication de la boucle $ digest, $ apply, la file d'attente $ evalAsync et la liste $ watch. Voici l'image qui accompagne le texte:

$digest loop

Quel que soit le code qui a accès à une portée - normalement les contrôleurs et les directives (leurs fonctions de liaison et / ou leurs contrôleurs) - peuvent mettre en place un "watchExpressionCette évaluation se produit chaque fois qu'AngularJS entre dans sa boucle $ digest (en particulier, la boucle "$ watch list") .Vous pouvez regarder les propriétés de la portée individuelle, vous pouvez définir une fonction pour regarder deux propriétés ensemble, vous pouvez regarder la longueur d'un tableau, etc.

Quand les choses se passent "dans AngularJS" - par exemple, vous tapez dans une zone de texte qui a la liaison de données bidirectionnelle AngularJS activée (par exemple, utilise ng-modèle), un feu de rappel $ http, etc - $ apply a déjà été appelé, donc nous Vous êtes dans le rectangle "AngularJS" de la figure ci-dessus. Toutes les watchExpressions seront évaluées (peut-être plus d'une fois - jusqu'à ce qu'aucun autre changement ne soit détecté).

Lorsque des événements se produisent "en dehors de AngularJS" - par exemple, vous utilisez bind () dans une directive, puis cet événement se déclenche, entraînant l'appel de votre rappel, ou certains feux de rappel enregistrés par jQuery - nous sommes toujours dans le rectangle "Native". Si le code de rappel modifie tout ce que regarde $ watch, appelez $ apply pour entrer dans le rectangle AngularJS, provoquant l'exécution de la boucle $ digest, et AngularJS remarquera le changement et fera sa magie.


152
2018-02-28 00:48



Ce blog a été couvert tout ce qui crée des exemples et des explications compréhensibles.

L'AngularJS $scope les fonctions $watch(), $digest() et $apply() sont quelques-unes des fonctions centrales dans AngularJS. Compréhension $watch(), $digest() et $apply() est essentiel pour comprendre AngularJS.

Lorsque vous créez une liaison de données quelque part dans votre vue à une variable sur l'objet $ scope, AngularJS crée une "surveillance" en interne. Une montre signifie que AngularJS regarde les changements dans la variable sur le $scope object. Le cadre «surveille» la variable. Les montres sont créées en utilisant $scope.$watch() fonction que je couvrirai plus tard dans ce texte.

Aux points clés de votre application, AngularJS appelle le $scope.$digest() fonction. Cette fonction parcourt toutes les montres et vérifie si l'une des variables observées a changé. Si une variable surveillée a changé, une fonction d'écouteur correspondante est appelée. La fonction d'écouteur effectue tout le travail nécessaire, par exemple en modifiant un texte HTML pour refléter la nouvelle valeur de la variable surveillée. Ainsi, le $digest() La fonction est ce qui déclenche la liaison de données à mettre à jour.

La plupart du temps AngularJS appellera $ scope. $ Watch () et $scope.$digest() fonctions pour vous, mais dans certaines situations, vous devrez peut-être les appeler vous-même. Par conséquent, il est vraiment bon de savoir comment ils fonctionnent.

le $scope.$apply() La fonction est utilisée pour exécuter du code, puis appeler $scope.$digest() après cela, toutes les montres sont vérifiées et les fonctions d'écoute correspondantes sont appelées. le $apply() La fonction est utile lors de l'intégration d'AngularJS avec un autre code.

Je vais entrer dans plus de détails sur le $watch(), $digest() et $apply() fonctionne dans le reste de ce texte.

$ watch ()

le $scope.watch() La fonction crée une montre d'une variable. Lorsque vous enregistrez une montre, vous passez deux fonctions en tant que paramètres de la $watch() fonction:

  • Une fonction de valeur
  • Une fonction d'écouteur

Voici un exemple:

$scope.$watch(function() {},
              function() {}
             );

La première fonction est la fonction de valeur et la deuxième fonction est la fonction d'écoute.

La fonction value doit renvoyer la valeur qui est surveillée. AngularJS peut alors vérifier la valeur retournée par rapport à la valeur que la fonction watch a retournée la dernière fois. De cette façon, AngularJS peut déterminer si la valeur a changé. Voici un exemple:

$scope.$watch(function(scope) { return scope.data.myVar },
              function() {}
             );

Cet exemple de fonction valule renvoie le $scope variable scope.data.myVar. Si la valeur de cette variable change, une valeur différente sera retournée et AngularJS appellera la fonction d'écouteur.

Remarquez comment la fonction value prend la portée en paramètre (sans le $ dans le nom). Via ce paramètre, la fonction de valeur peut accéder à $scope et ses variables. La fonction de valeur peut également regarder les variables globales si vous en avez besoin, mais le plus souvent vous regarderez un $scope variable.

La fonction d'écouteur doit faire ce qu'elle doit faire si la valeur a changé. Peut-être que vous avez besoin de changer le contenu d'une autre variable, ou définir le contenu d'un élément HTML ou quelque chose. Voici un exemple:

$scope.$watch(function(scope) { return scope.data.myVar },
              function(newValue, oldValue) {
                  document.getElementById("").innerHTML =
                      "" + newValue + "";
              }
             );

Cet exemple définit le code HTML interne d'un élément HTML sur la nouvelle valeur de la variable, incorporée dans l'élément b qui rend la valeur en gras. Bien sûr, vous auriez pu le faire en utilisant le code {{ data.myVar }, mais ce n'est qu'un exemple de ce que vous pouvez faire dans la fonction d'écoute.

$ digest ()

le $scope.$digest() fonction itère à travers toutes les montres dans le $scope object, et ses objets enfant $ scope (s'il en a). Quand $digest() itère sur les montres, il appelle la fonction de valeur pour chaque montre. Si la valeur renvoyée par la fonction value est différente de la valeur renvoyée la dernière fois qu'elle a été appelée, la fonction d'écoute de cette montre est appelée.

le $digest() La fonction est appelée quand AngularJS pense que c'est nécessaire. Par exemple, après qu'un gestionnaire de clic sur un bouton a été exécuté, ou après un AJAX call renvoie (après que la fonction callback done () / fail () a été exécutée).

Vous pouvez rencontrer des cas d'angle où AngularJS n'appelle pas le $digest() fonction pour vous. Vous détecterez généralement cela en notant que les liaisons de données ne mettent pas à jour les valeurs affichées. Dans ce cas, appelez $scope.$digest() et ça devrait marcher. Ou, vous pouvez peut-être utiliser $scope.$apply() Au lieu de cela, je vais expliquer dans la section suivante.

$ apply ()

le $scope.$apply() fonction prend une fonction en tant que paramètre qui est exécuté, et après cela $scope.$digest() est appelé en interne. Cela vous permet de vous assurer que toutes les montres sont vérifiées et que toutes les liaisons de données sont actualisées. Voici un $apply() Exemple:

$scope.$apply(function() {
    $scope.data.myVar = "Another value";
});

La fonction transmise à $apply() fonction comme paramètre va changer la valeur de $scope.data.myVar. Lorsque la fonction se termine AngularJS appellera le $scope.$digest() fonction de sorte que toutes les montres sont vérifiées pour les changements dans les valeurs surveillées.

Exemple

Pour illustrer comment $watch(), $digest() et $apply() fonctionne, regardez cet exemple:

<div ng-controller="myController">
    {{data.time}}

    <br/>
    <button ng-click="updateTime()">update time - ng-click</button>
    <button id="updateTimeButton"  >update time</button>
</div>


<script>
    var module       = angular.module("myapp", []);
    var myController1 = module.controller("myController", function($scope) {

        $scope.data = { time : new Date() };

        $scope.updateTime = function() {
            $scope.data.time = new Date();
        }

        document.getElementById("updateTimeButton")
                .addEventListener('click', function() {
            console.log("update time clicked");
            $scope.data.time = new Date();
        });
    });
</script>

son exemple lie le $scope.data.time variable à une directive d'interpolation qui fusionne la valeur de la variable dans la page HTML. Cette liaison crée une montre en interne sur le $scope.data.time variable.

L'exemple contient également deux boutons. Le premier bouton a un ng-click écouteur attaché à elle. Lorsque ce bouton est cliqué, le $scope.updateTime() fonction est appelée, et après que les appels AngularJS $scope.$digest() de sorte que les liaisons de données sont mises à jour.

Le deuxième bouton reçoit un écouteur d'événement JavaScript standard attaché à l'intérieur de la fonction du contrôleur. Lorsque le deuxième bouton est cliqué, cette fonction d'écoute est exécutée. Comme vous pouvez le voir, les fonctions d'écoute pour les deux boutons font presque la même chose, mais lorsque la fonction d'écoute du second bouton est appelée, la liaison de données n'est pas mise à jour. C'est parce que le $scope.$digest() n'est pas appelé après l'exécution de l'écouteur d'événement du second bouton. Ainsi, si vous cliquez sur le deuxième bouton, l'heure est mise à jour dans le $scope.data.time variable, mais la nouvelle heure n'est jamais affichée.

Pour résoudre ce problème, nous pouvons ajouter un $scope.$digest() appel à la dernière ligne de l'écouteur d'événement de bouton, comme ceci:

document.getElementById("updateTimeButton")
        .addEventListener('click', function() {
    console.log("update time clicked");
    $scope.data.time = new Date();
    $scope.$digest();
});

Au lieu d'appeler $digest() à l'intérieur de la fonction d'écouteur de bouton, vous pourriez également avoir utilisé le $apply() fonctionne comme ceci:

document.getElementById("updateTimeButton")
        .addEventListener('click', function() {
    $scope.$apply(function() {
        console.log("update time clicked");
        $scope.data.time = new Date();
    });
});

Remarquez comment le $scope.$apply() fonction est appelée à partir de l'écouteur d'événement de bouton, et comment la mise à jour de la $scope.data.timevariable est effectuée à l'intérieur de la fonction transmise en paramètre à la $apply() fonction. Quand le $apply() appel de fonction termine les appels AngularJS $digest() En interne, toutes les liaisons de données sont mises à jour.


53
2018-02-22 10:13



AngularJS étend cette events-loop, créant quelque chose appelé AngularJS context.

$ watch ()

Chaque fois que vous liez quelque chose dans l'interface utilisateur, vous insérez un $watch dans un $watch liste.

User: <input type="text" ng-model="user" />
Password: <input type="password" ng-model="pass" />

Ici nous avons $scope.user, qui est lié à la première entrée, et nous avons $scope.pass, qui est lié à la seconde. En faisant cela, nous ajoutons deux $watches à la $watch liste.

Quand notre modèle est chargé, AKA dans la phase de liaison, le compilateur va chercher toutes les directives et crée tous les $watches qui sont nécessaires.

AngularJS fournit $watch, $watchcollection et $watch(true). Voici un diagramme soigné expliquant tous les trois pris de observateurs en profondeur.

Enter image description here

angular.module('MY_APP', []).controller('MyCtrl', MyCtrl)
function MyCtrl($scope,$timeout) {
  $scope.users = [{"name": "vinoth"},{"name":"yusuf"},{"name":"rajini"}];

  $scope.$watch("users", function() {
    console.log("**** reference checkers $watch ****")
  });

  $scope.$watchCollection("users", function() {
    console.log("**** Collection  checkers $watchCollection ****")
  });

  $scope.$watch("users", function() {
    console.log("**** equality checkers with $watch(true) ****")
  }, true);

  $timeout(function(){
     console.log("Triggers All ")
     $scope.users = [];
     $scope.$digest();

     console.log("Triggers $watchCollection and $watch(true)")
     $scope.users.push({ name: 'Thalaivar'});
     $scope.$digest();

     console.log("Triggers $watch(true)")
     $scope.users[0].name = 'Superstar';
     $scope.$digest();
  });
}

http://jsfiddle.net/2Lyn0Lkb/

$digest boucle

Lorsque le navigateur reçoit un événement qui peut être géré par le contexte AngularJS, le $digest boucle sera tirée. Cette boucle est faite à partir de deux boucles plus petites. On traite le $evalAsync file d'attente, et l'autre traite le $watch list. le $digest bouclera la liste des $watch que nous avons

app.controller('MainCtrl', function() {
  $scope.name = "vinoth";

  $scope.changeFoo = function() {
      $scope.name = "Thalaivar";
  }
});

{{ name }}
<button ng-click="changeFoo()">Change the name</button>

Ici nous avons seulement un $watch car ng-click ne crée aucune montre.

Nous appuyons sur le bouton.

  1. Le navigateur reçoit un événement qui va entrer dans le contexte AngularJS
  2. le $digest la boucle sera exécutée et demandera à chaque $ de surveiller les changements.
  3. Depuis le $watch qui surveillait les changements dans $ scope.name rapporte un changement, il va forcer un autre $digest boucle.
  4. La nouvelle boucle ne signale rien.
  5. Le navigateur récupère le contrôle et met à jour le DOM reflétant la nouvelle valeur de $ scope.name
  6. L'important ici est que chaque événement qui entre dans le contexte AngularJS va exécuter un $digest boucle. Cela signifie que chaque fois que nous écrivons une lettre dans une entrée, la boucle va vérifier chaque $watch dans cette page.

$ apply ()

Si vous appelez $apply quand un événement est déclenché, il passera par le contexte angulaire, mais si vous ne l'appelez pas, il fonctionnera à l'extérieur. C'est aussi facile que ça. $apply appellera le $digest() boucle en interne et il parcourra toutes les montres pour s'assurer que le DOM est mis à jour avec la nouvelle valeur mise à jour.

le $apply() méthode déclenchera des observateurs sur l'ensemble $scope chaîne alors que le $digest() méthode ne déclenchera que des observateurs sur le courant $scope et son children. Quand aucun des plus haut $scope les objets doivent connaître les changements locaux, vous pouvez utiliser $digest().


37
2018-04-22 13:06



Il y a $watchGroup et $watchCollection ainsi que. Plus précisément, $watchGroup est vraiment utile si vous voulez appeler une fonction pour mettre à jour un objet qui a plusieurs propriétés dans une vue qui n'est pas un objet dom, par exemple. autre vue dans canvas, webGL ou requête serveur. Ici, la documentation lien.


17
2018-03-18 10:50



J'ai trouvé des vidéos très détaillées qui couvrent $watch, $apply, $digest et digérer les cycles dans:

Voici quelques diapositives utilisées dans ces vidéos pour expliquer les concepts (juste au cas où, si les liens ci-dessus sont supprimés / ne fonctionnent pas).

Enter image description here

Dans l'image ci-dessus, "$ scope.c" n'est pas surveillé car il n'est utilisé dans aucune des liaisons de données (dans le balisage). Les deux autres ($scope.a et $scope.b) sera regardé.

Enter image description here

À partir de l'image ci-dessus: En fonction de l'événement de navigateur respectif, AngularJS capture l'événement, effectue le cycle de digestion (passe en revue toutes les montres pour les changements), exécute les fonctions de surveillance et met à jour le DOM. Si ce n'est pas le cas, le cycle de digestion peut être déclenché manuellement en utilisant $apply ou $digest.

Plus à propos $apply et $digest:

Enter image description here


15
2017-11-20 16:28



Juste fini de lire tout ce qui précède, ennuyeux et somnolent (désolé mais c'est vrai). Très technique, en profondeur, détaillé et sec. Pourquoi j'écris? Parce que AngularJS est énorme, beaucoup de concepts interconnectés peuvent transformer n'importe qui en devenant fou. Je me suis souvent demandé, je ne suis pas assez intelligent pour les comprendre? Non! C'est parce que si peu peuvent expliquer la technologie dans un langage pour-dummie sans toutes les terminologies! D'accord, laissez-moi essayer:

1) Ce sont toutes des choses axées sur les événements. (J'entends le rire, mais continuez à lire)

Si vous ne savez pas ce qui est axé sur les événements est alors   pense que vous placez un bouton   sur la page, accrochez-le w / une fonction en utilisant "on-click", en attendant   les utilisateurs à cliquer dessus pour déclencher les actions que vous plantez dans le   fonction. Ou pensez à "trigger" de SQL Server / Oracle.

2) $ watch est "sur-clic". 

Ce qui est spécial, c'est qu'il faut 2 fonctions comme paramètres, le premier   donne la valeur de l'événement, le second prend la valeur en   considération...

3) $ digest est le patron qui vérifie inlassablement, bla-bla-bla mais un bon patron.

4) $ apply vous donne le chemin lorsque vous voulez le faire manuellement, comme une preuve d'échec (dans le cas où le clic ne se déclenche pas, vous le forcez à courir.)

Maintenant, faisons-le visuel. Imaginez ceci pour le rendre encore plus facile à saisir l'idée:

Dans un restaurant, 

- LES SERVEURS sont censés prendre les commandes des clients, c'est

$watch(
  function(){return orders;},
  function(){Kitchen make it;}
);

- GESTIONNAIRE courir pour s'assurer que tous les serveurs sont éveillés, sensibles à tout signe de changement de la part des clients. C'est $digest()

- Propriétaire a le pouvoir ultime de conduire tout le monde sur demande, c'est $apply()


10
2018-02-07 01:20