ng-change obtenir une nouvelle valeur et une valeur d'origine

118

J'utilise ng-options pour sélectionner des valeurs dans une liste déroulante. J'aimerais pouvoir comparer l'ancienne valeur à la nouvelle valeur. ng-change fonctionne bien pour saisir la nouvelle valeur du menu déroulant, mais comment puis-je obtenir à la fois la nouvelle valeur et la valeur d'origine?

<select ng-change="updateValue(user)" ng-model="user.id" ng-options="user.id as user.name for user in users"></select> 

Par exemple, disons que je voulais que le contrôleur enregistre, "Votre ancien nom d'utilisateur était BILL, votre nom d'utilisateur actuel est PHILLIPE."

Bailey Smith
la source
1
vérifiez ma réponse ici stackoverflow.com/questions/21909163/… pourrait être en double
bresleveloper
Je ne sais pas comment cela fonctionne administrativement, mais d'une manière ou d'une autre, les réponses du duplicata devraient être fusionnées avec celle-ci. bresleveloper est une bonne solution (à partir du duplicata) mais la réponse TGH devrait également être affichée. Le premier repose sur le fonctionnement du cadre, qui pourrait changer à l'avenir, tandis que le second est indépendant du cadre.
user1821052

Réponses:

279

Avec une {{expression}} angulaire, vous pouvez ajouter l'ancienne valeur user ou user.id à l'attribut ng-change sous forme de chaîne littérale:

<select ng-change="updateValue(user, '{{user.id}}')" 
        ng-model="user.id" ng-options="user.id as user.name for user in users">
</select>

Sur ngChange, le 1er argument de updateValue sera la nouvelle valeur utilisateur, le 2ème argument sera le littéral qui a été formé lors de la dernière mise à jour de la balise select par angular, avec l'ancienne valeur user.id.

db-inf
la source
6
Notez que l' userappel de la méthode in est celui de ng-model, et non de ng-options (peut être trompeur). Espérons que cette solution élégante fonctionnera également dans les futures versions d'angular :)
icl7126
15
Cela devrait être considéré comme nocif. Je viens de tomber sur un bug sale qui se produit lorsque user.id contient un caractère spécial (comme 'ou /). C'est parce que l'analyseur d'expression angulaire n'aime pas les expressions comme updateValue (user,' blah / blah ').
Antoine Banctel-Chevrel
2
Dans la fonction updateValue, $ scope.user.id contient déjà la nouvelle valeur sélectionnée - il n'est pas nécessaire de lui passer un paramètre pour la nouvelle valeur
Majix
@ LINQ2Vodka, je pense que cela ne fonctionne sans les guillemets que si le user.idest numérique ... cela ne fonctionnera pas s'il user.ids'agit d'une chaîne ou d'un guid
Tamas
1
beautiful :))))
Makatun
16

Vous pouvez également utiliser

<select ng-change="updateValue(user, oldValue)"     
       ng-init="oldValue=0"
       ng-focus="oldValue=user.id"
       ng-model="user.id" ng-options="user.id as user.name for user in users">
</select>
Umut Catal
la source
1
Cette réponse fonctionne très bien avec ng-repeat. Vous pouvez également utiliser ng-click à la place si l'élément sur lequel vous l'utilisez prend en charge ng-change mais pas ng-focus.
meticoeus
1
ng-init = "oldValue = 0" & ng-focus = "oldValue = user.id" a fait l'affaire pour moi.
thatzprem
14

Vous pouvez utiliser quelque chose comme ng-change = someMethod ({{user.id}}). En gardant votre valeur de côté {{expression}}, il évaluera l'expression en ligne et vous donnera la valeur actuelle (valeur avant l'appel de la méthode ng-change).

<select ng-model="selectedValue" ng-change="change(selectedValue, '{{selectedValue}}')">
Vivek Panday
la source
13

Gardez simplement une variable currentValue dans votre contrôleur que vous mettez à jour à chaque changement. Vous pouvez ensuite comparer cela à la nouvelle valeur à chaque fois avant de la mettre à jour. '

L'idée d'utiliser une montre est également bonne, mais je pense qu'une variable simple est la solution la plus simple et la plus logique.

TGH
la source
La montre est une opération peu coûteuse, j'ai aimé la réponse de db-inf .. c'est une solution de travail simple
Pramod Sharma
4
Meilleure réponse. Si vous êtes dans un ng-repeat, créez une variable dans le sous-scope en utilisant ng-init.
Romain F.
1
IMHO c'est la meilleure alternative. Puisque la récupération des anciennes valeurs n'est pas fournie par ngChange prête à l'emploi, des solutions comme celle de @ db-inf pourraient imploser sur les versions futures. En outre, cela ressemble à la responsabilité d'un contrôleur, semble étrange de le déléguer à la couche de vue.
Felipe Leão
9

Vous pouvez utiliser une montre à lunette:

$scope.$watch('user', function(newValue, oldValue) {
  // access new and old value here
  console.log("Your former user.name was "+oldValue.name+", you're current user name is "+newValue.name+".");
});

https://docs.angularjs.org/api/ng/type/$rootScope.Scope#$watch

tommybananas
la source
6
Je suis tombé sur un article qui déclare que la montre est beaucoup plus sale / inefficace que ng-change. benlesh.com/2013/10/title.html
Menios
5
D'après mon expérience, vous ne voulez presque jamais utiliser de montre
nardnob
2
Si la programmation était un art subjectif, vous pourriez avoir quelque chose là-bas. Hélas - il y a de nombreuses raisons pour lesquelles vous pourriez vouloir éviter ng-charge ou d'autres approches basées sur des directives, sans rapport avec le fait de faire les choses de manière "angulaire".
tommybananas du
2

Vous pouvez utiliser une montre à la place, car elle a l'ancienne et la nouvelle valeur, mais vous ajoutez ensuite au cycle de résumé.

Je garderais juste une deuxième variable dans le contrôleur et la définirais.

user12121234
la source
C'est un exemple assez trivial, je prendrais la lisibilité plutôt que de s'inquiéter d'un seul observateur dans ce cas. Encore une bonne chose dont on se lasse, je suppose.
tommybananas
1
Watch et ng-change ont en fait des comportements différents: ng-change ne détecte que les événements utilisateur, alors qu'il $watchse déclenche à chaque fois que la variable change. Les observateurs augmentent la complexité et sont enclins à créer des cycles de mise à jour lorsque le code modifie leurs valeurs.
Rhys van der Waerden
Je suis d'accord avec @Rhys van der Waerden ... cet article déclare que $ watch est un peu dangereux: benlesh.com/2013/10/title.html
Menios