ng-change obtiene un nuevo valor y un valor original

118

Estoy usando ng-options para seleccionar valores de un menú desplegable. Me gustaría poder comparar el valor anterior con el nuevo valor. ng-change funciona bien para obtener el nuevo valor del menú desplegable, pero ¿cómo puedo obtener tanto el nuevo valor como el valor original?

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

Por ejemplo, digamos que quería que el controlador registrara, "Su nombre de usuario anterior era BILL, su nombre de usuario actual es PHILLIPE".

Bailey Smith
fuente
1
verifique mi respuesta aquí stackoverflow.com/questions/21909163/… podría estar duplicado
bresleveloper
No estoy seguro de cómo funciona esto administrativamente, pero de alguna manera las respuestas del duplicado deberían fusionarse con esta. bresleveloper es una buena solución (del duplicado) pero la respuesta TGH también debería mostrarse. El primero se basa en el funcionamiento del marco, que podría cambiar en el futuro, mientras que el segundo es agnóstico del marco.
user1821052

Respuestas:

279

Con una {{expresión}} angular, puede agregar el antiguo valor user o user.id al atributo ng-change como una cadena literal:

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

En ngChange, el primer argumento para updateValue será el nuevo valor de usuario, el segundo argumento será el literal que se formó cuando la etiqueta de selección se actualizó por última vez por angular, con el antiguo valor user.id.

db-inf
fuente
6
Tenga useren cuenta que la llamada al método in es la de ng-model, y no de ng-options (puede ser engañosa). Con suerte, esta elegante solución funcionará también en futuras versiones de angular :)
icl7126
15
Esto debe considerarse perjudicial. Me encontré con un error sucio que ocurre cuando user.id contiene un carácter especial (como 'o /). Esto se debe a que al analizador de expresiones angulares no le gustan las expresiones como updateValue (usuario,' blah / blah ').
Antoine Banctel-Chevrel
2
En la función updateValue, $ scope.user.id ya contiene el valor recién seleccionado; no es necesario pasarle un parámetro para el nuevo valor
Majix
@ LINQ2Vodka, creo que solo funciona sin las comillas si user.ides numérico ... no funcionará si user.ides una cadena o un guid
Tamas
1
hermosa :))))
Makatun
16

También puedes 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
fuente
1
Esta respuesta funciona muy bien con ng-repeat. También puede usar ng-click en su lugar si el elemento en el que está usando esto admite ng-change pero no ng-focus.
meticoeus
1
ng-init = "oldValue = 0" & ng-focus = "oldValue = user.id" hizo el truco por mí.
thatzprem
14

Puede usar algo como ng-change = someMethod ({{user.id}}). Al mantener su valor en el lado {{expresión}}, evaluará la expresión en línea y le dará el valor actual (valor antes de que se llame al método ng-change).

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

Simplemente mantenga una variable currentValue en su controlador que actualice en cada cambio. Luego puede comparar eso con el nuevo valor cada vez que lo actualice. '

La idea de usar un reloj también es buena, pero creo que una variable simple es la solución más simple y lógica.

TGH
fuente
El reloj es una operación poco costosa, me gustó la respuesta de db-inf .. es una solución de trabajo simple
Pramod Sharma
4
La mejor respuesta. Si está dentro de una repetición ng, cree una variable en el subámbito usando ng-init.
Romain F.
1
En mi humilde opinión, esta es la mejor alternativa. Dado que ngChange no proporciona la recuperación de valores antiguos, soluciones como la de @ db-inf podrían implosionar en versiones futuras. Además, esto suena como la responsabilidad de un controlador, parece extraño delegarlo en la capa de vista.
Felipe Leão
9

Puede utilizar un reloj de alcance:

$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
fuente
6
Me encontré con un artículo que afirma que el reloj es mucho más sucio / ineficiente en comparación con ng-change. benlesh.com/2013/10/title.html
Menios
5
En mi experiencia, casi nunca quieres usar un reloj
nardnob
2
Si la programación fuera un arte subjetivo, es posible que tenga algo allí. Por desgracia, hay muchas razones por las que es posible que desee evitar la carga ng u otros enfoques basados ​​en directivas, no relacionados con hacer las cosas de forma "angular".
tommybananas
2

En su lugar, podría usar un reloj, porque tiene el valor anterior y el nuevo, pero luego está agregando al ciclo de resumen.

Solo mantendría una segunda variable en el controlador y la configuraría.

usuario12121234
fuente
Este es un ejemplo bastante trivial, preferiría la legibilidad a preocuparme por un solo observador en este caso. Todavía es bueno estar cansado, supongo.
tommybananas
1
Watch y ng-change en realidad tienen comportamientos diferentes: ng-change solo detecta eventos de usuario, mientras que se $watchactivará cada vez que cambie la variable. Los observadores aumentan la complejidad y tienden a crear ciclos de actualización cuando el código cambia sus valores.
Rhys van der Waerden
Estoy de acuerdo con @Rhys van der Waerden ... este artículo afirma que $ watch es un poco peligroso: benlesh.com/2013/10/title.html
Menios