7
votes

I am new to angular and I am learning Angular 6. I understood about ngModel. But while I was experimenting with ngModelChange, some questions raised.

I have an html element HTML

<input #input  type="text" [value]="name" [(ngModel)] ="name" (ngModelChange) ="change(input.value)"/>

Typescript

change(event :any) {
    this.name = event;
    console.log(this.name);
}

Upon changing the value in the input , I can see the changes with the name property.

When I changed the html code to

HTML

<input #input type="text" [value]="name"  [ngModel] ="name" 
(ngModelChange)="change(input.value)" />
{{ name }}

TS

change(event :any) {
    this.name = event;
    console.log(this.name);
}

It's working fine as expected in the console and in the UI.

Question 1

<input #input  type="text" [value]="name" [(ngModel)] ="name" 
(ngModelChange) ="change(input.value)"/>

&

<input #input type="text" [value]="name"  [ngModel] ="name" 
(ngModelChange)="change(input.value)" />

are same??

Question 2.

When I remove the [ngModel] directive. The ngModelChange is not getting triggered. Is it mandatory to have [ngModel]? If yes,Why?

HTML

<input #input type="text" [value]="name" 
(ngModelChange)="change(input.value)" />
<br/>
<br/>
{{ name }}

TS

change(event: any) {
     this.name = event;
     console.log(this.name);
 }

This would be a great help. Thanks in Advance.

3

3 Answers

6
votes

The [()] syntax is easy to demonstrate when the element has a settable property called x and a corresponding event named xChange. Here's a SizerComponent that fits this pattern. It has a size value property and a companion sizeChange event

https://angular.io/guide/template-syntax#basics-of-two-way-binding

So, they are equivalent.

<input [(ngModel)]="name"/>
<input [ngModel]="name" (ngModelChange) ="name = $event"/>

But if there is no corresponding property, then xChange will not work.

<input (ngModelChange) ="name = $event"/>
3
votes

ad Question 1) They are not the same as you write it. Writing

<input [(ngModel)]="name" (ngModelChange)="change(input.value)"/>

does not make sense really if you just want to set the variables value, because the (banana-in-a-box) expression [(ngModel)] itself is just syntactic sugar for

[ngModel]="name" (ngModelChange)="name = $event"

So your example would result in:

<input [ngModel]="name" (ngModelChange)="name = $event" (ngModelChange)="change(input.value)"/>

ad Question 2) Yes you need at least the [ngModel]="name" expression to be able to activate the Angular directive. We can see that in the selector of the NgModel directive in the Angular source itself:

@Directive({
  selector: '[ngModel]:not([formControlName]):not([formControl])',
  providers: [formControlBinding],
  exportAs: 'ngModel'
})
export class NgModel extends NgControl implements OnChanges,
    OnDestroy {
    ...
    ...
    @Output('ngModelChange') update = new EventEmitter();
    ...
2
votes

I want to add on the previous answers that mixing [(ngModel)] (banana in a box) and (ngModelChange) can have a use case, because (ngModelChange) will still be fired after the banana in a box updated your model.

For example, if for some reason you want to trigger a nameChange EventEmitter every time the name is changed you could write it this way

<input [(ngModel)]="name" (ngModelChange)="nameChange.emit(name)" />

Quick stackblitz to demonstrate that the model is already updated when (ngModelChange) is fired : https://stackblitz.com/edit/angular-teu1am