ng-change obtém novo valor e valor original

118

Estou usando opções de ng para selecionar valores em um menu suspenso. Eu gostaria de poder comparar o valor antigo com o novo. ng-change funciona bem para obter o novo valor do pull down, mas como posso obter o novo valor e o valor original?

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

Por exemplo, digamos que eu queira que o controlador registre, "Seu nome de usuário anterior era BILL, seu nome de usuário atual é PHILLIPE."

Bailey Smith
fonte
1
verifique minha resposta aqui stackoverflow.com/questions/21909163/… pode ser duplicado
bresleveloper
não tenho certeza de como isso funciona administrativamente, mas de alguma forma as respostas da duplicata devem ser mescladas com esta. bresleveloper é uma boa solução (da duplicata), mas a resposta TGH deve ser mostrada também. O primeiro depende do funcionamento do framework, que pode mudar no futuro, enquanto o segundo é agnóstico do framework.
user1821052

Respostas:

279

Com uma {{expression}} angular, você pode adicionar o valor user.id ou user.id antigo ao atributo ng-change como uma string literal:

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

No ngChange, o primeiro argumento para updateValue será o novo valor do usuário, o segundo argumento será o literal que foi formado quando a tag de seleção foi atualizada pela última vez pelo angular, com o antigo valor user.id.

db-inf
fonte
6
Observe que a userchamada do método in é de ng-model, e não de opções de ng (pode ser enganoso). Esperançosamente, esta solução elegante funcionará também em versões futuras do angular :)
icl7126
15
Isso deve ser considerado prejudicial. Acabei de encontrar um bug incorreto que ocorre quando user.id contém um caractere especial (como 'ou /). Isso ocorre porque o analisador de expressão angular não gosta de expressões como updateValue (usuário,' blá / blá ').
Antoine Banctel-Chevrel
2
Na função updateValue, $ scope.user.id já contém o valor recém-selecionado - não há necessidade de passar um parâmetro para o novo valor para ele
Majix
@ LINQ2Vodka, acho que só funciona sem as aspas se user.idfor numérico ... não vai funcionar se user.idfor string ou guid
Tamas
1
lindo :))))
Makatun de
16

Você também pode usar

<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
fonte
1
Esta resposta funciona muito bem com ng-repeat. Você também pode usar ng-click em vez disso se o elemento que você está usando suportar ng-change, mas não ng-focus.
meticoeus
1
ng-init = "oldValue = 0" & ng-focus = "oldValue = user.id" funcionou para mim.
Thatzprem
14

Você pode usar algo como ng-change = someMethod ({{user.id}}). Ao manter seu valor no lado {{expression}}, ele avaliará a expressão em linha e fornecerá o valor atual (valor antes do método ng-change ser chamado).

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

Basta manter uma variável currentValue em seu controlador que você atualiza a cada alteração. Você pode então comparar esse valor com o novo sempre antes de atualizá-lo. '

A ideia de usar um relógio também é boa, mas acho que uma variável simples é a solução mais simples e lógica.

TGH
fonte
Assistir é uma operação um pouco cara, gostei da resposta de db-inf .. é uma solução de trabalho simples
Pramod Sharma
4
Melhor resposta. Se você estiver dentro de um ng-repeat, crie uma variável no sub-escopo usando ng-init.
Romain F.
1
IMHO esta é a melhor alternativa. Visto que a recuperação de valores antigos não é fornecida pelo ngChange pronto para uso, soluções como a de @ db-inf podem implodir em versões futuras. Além disso, isso soa como responsabilidade de um controlador, parece estranho delegar para a camada de visualização.
Felipe Leão
9

Você pode usar um osciloscópio:

$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
fonte
6
Eu encontrei um artigo que afirma que o relógio é muito mais sujo / ineficiente em comparação com o ng-change. benlesh.com/2013/10/title.html
Menios
5
Pela
2
Se a programação fosse uma arte subjetiva, você poderia ter algo lá. Infelizmente - há muitas razões pelas quais você pode querer evitar ng-charge ou outras abordagens baseadas em diretivas, não relacionadas a fazer as coisas da maneira "angular".
tommybananas
2

Você poderia usar um relógio em vez disso, porque ele tem o valor antigo e o novo, mas então você está adicionando ao ciclo de resumo.

Eu apenas manteria uma segunda variável no controlador e a definiria.

user12121234
fonte
Este é um exemplo bastante trivial, eu consideraria a legibilidade ao invés de me preocupar com um único observador neste caso. Ainda é uma coisa boa para se cansar, suponho.
tommybananas
1
Watch e ng-change na verdade têm comportamentos diferentes: ng-change apenas detecta eventos do usuário, enquanto $watchdispara toda vez que a variável muda. Os observadores aumentam a complexidade e tendem a criar ciclos de atualização quando o código altera seus valores.
Rhys van der Waerden
Concordo com @Rhys van der Waerden ... este artigo afirma que $ watch é um pouco perigoso: benlesh.com/2013/10/title.html
Menios