Reputation: 33
I am using simple ngModelChange
event on input
box where updated value is passed on event and updated back after some operations.
<input placeholder="" #TestInput="ngModel"
name="TestInput"
[(ngModel)]="testInput"
(ngModelChange)="onTestInputChange($event)" >
and in component
testInput: string;
onTestInputChange(event) {
this.testInput = this.testInput === ''
? 'cat'
: this.testInput==='tiger'
? this.testInput
: 'lion';
}
Steps:
testInput
is updated.https://stackblitz.com/edit/angular-ivy-aqpcjx
Also tried change
event also, no luck.
Thanks!!
Upvotes: 0
Views: 1526
Reputation: 2875
The problem is that you're using two-way binding on your ngModel, so both your ngModel and ngModelChange are interacting with the model change event. You can read more from this answer:
ngModel changes, ngModelChange is not called
Looking at that answer, you'll see they recommend removing the two-way binding. If you don't need two way binding for ngModel, make it only settable by changing the [()]
to just []
. But in your example this doesn't give the desired effect.
What I recommend is simply using the DOM level change event to run your event listener, so change (ngModelChange)
to simply (change)
.
<input placeholder="" #TestInput="ngModel"
name="TestInput"
[(ngModel)]="testInput"
(change)="onTestInputChange($event)" >
-- EDIT --
The above is not actually correct. The real issue is to do with when the view is updated – as long as ngModel believes it hasn't changed, it doesn't update the view (even though we can see for ourselves that the visible value of the input is different).
So when you set the value to ''
the value of testInput
becomes 'cat'
. You delete again, and testInput
is set to 'cat'
again. NgModel believes nothing has changed so the view is not updated (even though we see the change on the input).
You can force Angular to fix this by running detectChanges
before testInput is reset to 'cat'
. To do this, you want to inject changeDetectorRef
, like so:
import { Component, VERSION, ChangeDetectorRef } from '@angular/core';
@Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: [ './app.component.css' ]
})
export class AppComponent {
name = 'Angular ' + VERSION.major;
testInput: string;
constructor(private changeDetectorRef: ChangeDetectorRef) {
}
//issue is when testInput blank valus is assigned as 'cat' again,
// but not updated in input element.
onTestInputChange(event) {
this.changeDetectorRef.detectChanges();
this.testInput = this.testInput === ''
? 'cat'
: this.testInput === 'tiger'
? this.testInput
: 'lion';
}
}
Now the view will be updated with every change to ngModel. Here's the fork:
https://stackblitz.com/edit/angular-ivy-bd2mu5?file=src%2Fapp%2Fapp.component.ts
That said, I still believe the (change)
solution is better because it's more user friendly to wait for blur. Otherwise, they'll never even get the chance to type 'tiger' because it will always be switched to 'lion'.
Upvotes: 2
Reputation:
I recently answered a similiar question and iam still unsure as to why neither your solution nor input
doesn't work.
To get the immediate result without first having to blur your input, you can reference your input element and change it's value during the input
event.
<input placeholder="" #TestInput
name="TestInput"
(input)="onTestInputChange(TestInput)" >
onTestInputChange(input) {
input.value = input.value === ''
? 'cat'
: input.value ==='tiger'
? input.value
: 'lion';
}
https://stackblitz.com/edit/angular-ivy-gbchzy?file=src/app/app.component.ts
Upvotes: 1