AngularJS: détecte automatiquement les changements de modèle

103

Supposons que je veuille faire quelque chose comme exécuter automatiquement du code (comme enregistrer des données sur un serveur) chaque fois que les valeurs d'un modèle changent. Est-ce que le seul moyen de le faire est de définir quelque chose comme ng-changesur chaque commande qui pourrait éventuellement modifier le modèle?

C'est-à-dire qu'avec les vues, les choses changent à mesure que le modèle est modifié sans avoir à connecter explicitement quoi que ce soit. Existe-t-il un analogue à la capacité d'exécuter du code qui enregistre sur un serveur? Quelque chose comme

myModel.on('change', function() {
  $.post("/my-url", ...);
});

comme vous pourriez le voir avec quelque chose comme backbone.

Alec
la source

Réponses:

151

Dans les vues avec {{}}et / ou ng-model, Angular met en place $watch()es pour vous dans les coulisses.

Par défaut, $watchcompare par référence. Si vous définissez le troisième paramètre $watchà true, angulaire sera plutôt « peu profonde » regarder l'objet de modifications. Pour les tableaux, cela signifie comparer les éléments du tableau, pour les mappages d'objets, cela signifie surveiller les propriétés. Donc, cela devrait faire ce que vous voulez:

$scope.$watch('myModel', function() { ... }, true);

Mise à jour : Angular v1.2 a ajouté une nouvelle méthode pour cela, `$ watchCollection () :

$scope.$watchCollection('myModel', function() { ... });

Notez que le mot "superficiel" est utilisé pour décrire la comparaison plutôt que "profond" car les références ne sont pas suivies - par exemple, si l'objet surveillé contient une valeur de propriété qui est une référence à un autre objet, cette référence n'est pas suivie pour comparer l'autre objet.

Mark Rajcok
la source
1
Ah, super! Y a-t-il une raison pour laquelle cela ne semble pas être tout ce que documenté (c'est-à-dire, je ne pense pas que l'un des tutoriels sur le site angulaire a mentionné la configuration directe de $ montres)? Y a-t-il quelque chose de mauvais à ce sujet qui ferait de la configuration (potentiellement plusieurs) des ng-changecrochets sur les contrôles d'entrée une meilleure idée?
Alec
12
Ouais, ce serait bien si le tutoriel principal mentionnait $ watch quelque part. Ce qui est «mauvais» dans cette approche, c'est qu'elle peut prendre du temps si votre modèle est volumineux (chaque cycle de résumé - chaque frappe dans un champ de saisie - entraînera une vérification approfondie de ce modèle, peut-être plusieurs fois) . Dans ce cas, des $ watch () es sélectifs ou un changement de ng sélectif seraient meilleurs.
Mark Rajcok
8

Et si vous avez besoin de styliser vos éléments de formulaire en fonction de leur état (modifié / non modifié) de manière dynamique ou pour tester si certaines valeurs ont réellement changé, vous pouvez utiliser le module suivant, développé par moi-même: https://github.com/betsol / angular-input-modified

Il ajoute des propriétés et des méthodes supplémentaires au formulaire et à ses éléments enfants. Avec lui, vous pouvez tester si un élément contient de nouvelles données ou même tester si tout le formulaire contient de nouvelles données non enregistrées.

Vous pouvez configurer la montre suivante: $scope.$watch('myForm.modified', handler)et votre gestionnaire sera appelé si certains éléments du formulaire contiennent réellement de nouvelles données ou s'il est retourné à son état initial.

En outre, vous pouvez utiliser la modifiedpropriété d'éléments de formulaire individuels pour réduire réellement la quantité de données envoyées à un serveur via un appel AJAX. Il n'est pas nécessaire d'envoyer des données inchangées.

En prime, vous pouvez rétablir votre formulaire à son état initial via un appel au formulaire. reset() méthode .

Vous pouvez trouver la démo du module ici: http://plnkr.co/edit/g2MDXv81OOBuGo6ORvdt?p=preview

À votre santé!

Slava Fomin II
la source
Existe-t-il un moyen de vérifier cela dans le contrôleur. par exemple si le clic sur le bouton x puis-je faire comme si (myform.modified) show confirmation popup?
Flash
Bien sûr, passez simplement FormController à la fonction de votre contrôleur: <form name="myForm">, <button ng-click="vm.doSomething(myForm)">.
Slava Fomin II
merci cela ne fera quelque chose que si le formulaire a été modifié, non?
Flash
Cela passera FormControllerà la doSomething()fonction de votre contrôleur. Vous pouvez faire tout ce que vous voulez avec cette fonction à l'intérieur de cette fonction, par exemple vérifier si le formulaire est réellement modifié en vérifiant la FormController.modifiedpropriété booléenne.
Slava Fomin II
Merci! Belle fonctionnalité
Flash