Angular 2 ngModelChange old value
Asked Answered
A

3

18

Can someone please tell me what is the best practice for comparing ngModel old and new value?

In angular 1:

$scope.$watch('someProperty', funciton(oldVal, newVal){
    // code goes here
})

I am asking this because (ngModelChange) never brings me the oldVal , only the newVal.

In my case, I am using ngModel in a <select> tag and compare the old selection with the new one:

<select [(ngModel)]="current" (ngModelChange)="onModelChange($event)">
     <option *ngFor="let item of myArray" [ngValue]="item">{{item.name}} </option>
</select>
Arda answered 9/1, 2017 at 8:47 Comment(0)
H
19

This might work

(ngModelChange)="onModelChange(oldVal, $event); oldVal = $event;"

or

(ngModelChange)="onModelChange($event)"
oldValue:string;
onModelChange(event) {
  if(this.oldValue != event) {
    ...
  }
  this.oldValue = event;
}
Humic answered 9/1, 2017 at 8:49 Comment(5)
I tried this but the oldVal param is undefined. I am using this comparation in a <select> tag (please look at my edited post)Arda
Just declare a variable with this name in the components class. I added it to my code (in the 2nd example)Allargando
Ok, i get it now. but this solution seems to be very manually, are you sure that is the best practice? there is nothing delivered by angular 2 for getting the oldVal?Arda
No, Angular only provides $event or if you use [ngModel]="myValue" updates the myValue property with the new value. If you use [myProp]="someValue" binding to an @Input() myProp;, then when the binding is updated ngOnChanges(changes), changes contains the old value as well, but that doesn't apply to your situation, it is only for binding from parent to child.Allargando
In my case, select value is already set, so the value of this.oldValue is undefined, because the onModelChange would be run for the first time. Is there a workaround for this as well?Hoatzin
S
16

Just for the future

we need to observe that [(ngModel)]="hero.name" is just a short-cut that can be de-sugared to: [ngModel]="hero.name" (ngModelChange)="hero.name = $event".

So if we de-sugar code we would end up with:

<select (ngModelChange)="onModelChange()" [ngModel]="hero.name" (ngModelChange)="hero.name = $event">

or

<[ngModel]="hero.name" (ngModelChange)="hero.name = $event" select (ngModelChange)="onModelChange()">

If you inspect the above code you will notice that we end up with 2 ngModelChange events and those need to be executed in some order.

Summing up: If you place ngModelChange before ngModel, you get the $event as the new value, but your model object still holds previous value. If you place it after ngModel, the model will already have the new value.

SOURCE

Sample stack blitz: https://stackblitz.com/edit/angular-ivy-zlhwex

Shoemake answered 25/7, 2019 at 6:50 Comment(1)
Wow, I had no idea that these would literally fire sequentially based on their position in the template. A great help. Here's hoping they don't standardize the execution order for this at a later time...Balinese
A
9

Example with input field...

<div *ngFor="let value of values">{{value}}
    <input [(ngModel)]="value" (focus)="old=value" (ngModelchange)="doSomething(old, value)">
</div>

doSomething(oldVal, newVal) {
    // some code
}
Aspirant answered 9/1, 2017 at 8:49 Comment(1)
I am using this comparation in a <select> tag (see my edited post). i guess (focus) is not relevant anymore. can you please write an example with a select tag?Arda

© 2022 - 2025 — McMap. All rights reserved.