In this post we’re going to cover the difference between (change)
and (ngModelChange)
events with an <input>
inside an Angular component.
First we need to understand that change
is not an “Angular event”, it’s a DOM event.
Whereas ngModelChange
is an Angular event. It fires when ngModel
changes.
Essentially, we want to learn the difference between these and learn which one to use:
<input [value]="foo" (change)="changeFn($event)">
<input [ngModel]="bar" (ngModelChange)="modelChangeFn($event)">
The answer already lives above in our ngModel
.
The (change)
binding is listening for a DOM event called change
, which will give us exactly what we’d expect in “plain JavaScript DOM” outside of the Angular system. Our changeFn($event)
would then be given the regular Event
object.
But (ngModelChange)
is inside the Angular system, and we can further understand the difference between the two events by looking at the ngModel directive. The modelChangeFn($event)
I’ve passed in will also give us something different to the previous changeFn($event)
too, we’ll come onto this!
Before we do that, here’s how we’d typically use ngModel
with its shorthand binding and event syntax (understanding this will make our lives easier):
<input [(ngModel)]="bar">
The above syntax is simply shorthand for an event callback and a model set all at once.
When the user wants to change the model, by entering text into the input, the event callback fires and sets the new value to the model.
So why (ngModelChange)
? If we look at the ngModel directive source code we can see an @Output()
(because it’s a directive it has an output). Here’s what the source reveals:
export class NgModel {
//...
@Output('ngModelChange') update = new EventEmitter();
//...
}
The NgModel
class has the update
property with an EventEmitter
instance bound to it. This means we can’t use (ngModelChange)
without ngModel
.
Whereas the (change)
event can be used anywhere, and I’ve demonstrated that above with the [value]
property binding instead.
It’s also worth noting that (ngModelChange)
will only fire when the model is intended to be updated. Again here’s a piece from the ngModel source code:
export class NgModel {
//...
viewToModelUpdate(newValue: any): void {
this.viewModel = newValue;
this.update.emit(newValue);
}
//...
}
Something inside Angular will call viewToModelUpdate
as we’re taking the model from our view (the input) and wanting to pass that update to the model, a well named method I’d say.
Really, if you’re using ngModel
, you can just use the normal two-way binding syntax [(ngModel)]
to sync both view and model at all times.
Comparing $event arguments
Let’s have a look at the differences that (change) and (ngModelChange)
both give us. I’ve created this component to demonstrate the differences:
@Component({
selector: 'my-app',
template: `
<div>
<input [value]="foo" (change)="changeFn($event)">
<p>{{ foo }}</p>
<input [ngModel]="bar" (ngModelChange)="modelChangeFn($event)">
<p>{{ bar }}</p>
</div>
`
})
export class AppComponent {
foo = 'Hello';
bar = 'World';
changeFn(e) {
this.foo = e.target.value;
}
modelChangeFn(value) {
this.bar = value;
}
}
There are a few things to note here:
- Using
(change)
will only fire when the user has blurred the input - Using
(ngModelChange)
essentially is listening to theinput
event, and setting the model if a user types, pastes or changes the input’s value
And also:
- With
(change)
we need to use thee.target.value
as we’re given a plain DOM Event. From there, we can set the model value internally in the component! - With
(ngModelChange)
we are given the value as juste
, which you could rename tovalue
or something you prefer.
What about when the event fires and the model value is set?
- The (change)=”changeFn($)” will fire after the value bound to [(ngModel)] has changed
- The (ngModelChange)=”modelChangeFn($event)” will fire before the value bound to [(ngModel)] has changed.
Start typing in the live Stackblitz demo to see the models reflect in different ways:
Free eBook
Directives, simple right? Wrong! On the outside they look simple, but even skilled Angular devs haven’t grasped every concept in this eBook.
- Observables and Async Pipe
- Identity Checking and Performance
- Web Components <ng-template> syntax
- <ng-container> and Observable Composition
- Advanced Rendering Patterns
- Setters and Getters for Styles and Class Bindings
Summary
Really, it comes down to using ngModel
or not. If you’re using [(ngModel)]
then you don’t need to worry about this, otherwise use (change)
if you really want to provide some level of custom event
or intercept the event before setting the model.
It’s always great to explore the source code, and I’d encourage you to check out the links above in your own time to learn a little more.
If you are serious about your Angular skills, your next step is to take a look at my Angular courses where you’ll learn Angular, TypeScript, RxJS and state management principles from beginning to expert level.
Now we fully understand the difference between (change)
and (ngModelChange)
! I hope you enjoyed the post, thanks for reading!