(ngModelChange) does not update the UI for specific input

select ngmodelchange not working
ng-model not updating input value
ng-model not updating input angular2
angular input not updating
change or ngmodelchange
ngmodelchange for input
angular input change not detected
ngmodel not working on input

I have an input field where the user can enter the rate of something.

When the user enters a value, I want it to be displayed after rounding it off and then the updated value to be stored on the backing model in ts file.

Using an Angular pipe isn't good for this since a pipe in one directional and the updated value won't be reflected on the model.

So to make it bidirectional, I'm doing the following:

<input type="text" [ngModel]="model.rate" (ngModelChange)="model.rate=roundRate($event)" name="rate" />

The roundDate function looks like this

roundRate(value) {
    return Math.round(value);
}

Now when I enter values like 5.6, 7.8, 9.5 etc they're all rounded off, displayed and stored on the model to 6, 8 and 10 respectively, which is the expected behavior.

The problem starts when I enter 2.1, 3.4, 5.3 etc. In this case, the roundRate function gets called and it returns the value after rounding off. But the values shown on screen are still the old values (2.1, 3.4, 5.3)

I inspected the input element on Chrome and found that the ng-reflect-model property was getting updated to the expected values (2, 3, 5).

<input _ngcontent-c39="" name="rate" type="text" ng-reflect-name="rate" ng-reflect-model="5" class="ng-valid ng-dirty ng-touched">

Can someone please explain what is happening here and despite the ng-reflect-model property getting updated why the screen still shows the old values?

Thanks for your help!

For a cleaner implementation, just use the (change) @Output property and [(ngModel)]. The implementation of roundRate will change something like this:

import { Component } from '@angular/core';

@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {

  model = { rate: null };

  roundRate() {
    this.model.rate = Math.round(+this.model.rate);
  }
}

And in template:

<input type="text" [(ngModel)]="model.rate" (change)="roundRate()" name="rate" />

PS: This will update the value only once you blur from your input field


Here's a Sample StackBlitz for your ref.

(ngModelChange) does not update the UI for specific input, Since it isn't update model.rate value, whatever you enter further are just ignore by ngModel binding, and shown inside input field. Check for 4.6, 4.8 works  (ngModelChange) does not update the UI for specific input 2

Begin with a closer look at the ngModel directive API, you will see that ngModel is @Input binding which accepts some value as model variable. At the time of initializing ngModel control it creates FormControl implicitly.

public readonly control: FormControl = new FormControl();

The magic of updating model value happens from ngOnChanges hook, this way it sync view value with model value. If you take a closer look at ngOnChanges hook, you will find that, it validates input and apply other checks as well, afterwards it strictly checks that if value of ngModel value is really changed using isPropertyUpdated method.

ngOnChanges - ngModel directive

ngOnChanges(changes: SimpleChanges) {
    this._checkForErrors();
    if (!this._registered) this._setUpControl();
    if ('isDisabled' in changes) {
      this._updateDisabled(changes);
    }

    if (isPropertyUpdated(changes, this.viewModel)) {
      this._updateValue(this.model); // helps to update 
      this.viewModel = this.model;
    }
}

private _updateValue(value: any): void {
    resolvedPromise.then(() => { 
      // set value will set form control
      this.control.setValue(value, {emitViewToModelChange: false}); 
    });
}

But to make it happen Angular should recognize the changes during change detection cycle. And since we hasn't changed our model it won't trigger ngOnChanges hook:

What I explained till now was API part. Lets come back to the question.

Try below snippet in stackblitz, what our expectation would be. On input value change it should set that value to 10 itself.

<input type="text" 
  [ngModel]="model.rate" 
  (ngModelChange)="model.rate = 10"
  name="rate" />

Unfortunately, it doesn't happen in that way, you will see that on initial typing any number, it will change input value to 10 and later whatever you will type will keep on appending to number input. Ahh, wondering why?

Lets go back again to original question,

<input type="text" 
  [ngModel]="model.rate" 
  (ngModelChange)="model.rate=roundRate($event)"
  name="rate" />
 {{model.rate}}

ngModel used as one way binding. Expected behavior is, whatever values assigned to the model.rate should be reflected inside the input. Let's try to enter 1.1 you will see that it shows us value 1.1. Now try to enter 1.2, results in 1.2 results in 1. Wondering why? But certainly model.rate bindings update correctly. Similarly Check for 4.6, 4.8 result in 5 which works perfect.

Let's break it down above example, what happens when you try to enter 1.1.

  1. type 1 => model.rate becomes 1
  2. type 1. => model.rate stays 1
  3. type 1.1 => model.rate stays 1

Eventually when you type 1.1 or 1.2 model value stays 1 since we Math.round value. Since it isn't update model.rate value, whatever you enter further are just ignore by ngModel binding, and shown inside input field.

Check for 4.6, 4.8 works perfectly. Why? break it down step wise

  1. type 4 => model.rate becomes 4
  2. type 4. => model.rate stays 4
  3. type 4.6 => model.rate becomes 5

Over here when you enter 4.6 in textbox, Math.round value becomes 5. which is change in model.rate(ngModel) value would result in update in input field value

Now start reading answer again, the technical aspect explained initially will be cleared as well.

Note: While reading an answer follow the links provided to snippet, it may help you understand it more precisely.


To make it working you can try updating your fields on blur/change where this event fire up on focus out of fields like Sid's answer. It worked because you're updating model once when field is focused out.

But it works only once. To keep updates constantly we can do some trick:

this.model.rate = new String(Math.round(value));

which will result in a new object reference each time we round our value.

Snippet in Stackblitz

ngModel change binding on Input type="number" not working · Issue , In a Component, the following does not reflect the change in the UI. <input type="​number" [(ngModel)]="element.value" (change)="onChange($  The model updates correctly but the input value doesn't change even if there is the [ngModel]. This is the plnkr In the example if you type more than 10 characters &amp;#39;name&amp;#39; will be truncated to 10.

In Angular change detection strategy help to reflect changes on UI.

Please use below code:

Step 1: Import ChangeDetectorRef in your component

import { ChangeDetectorRef} from angular/core';

Step 2: Create instance of ChangeDetectorRef on constructor.

constructor(private ref: ChangeDetectorRef){
}

Step 3: Call where you are updating value.

this.ref.detectChanges();

Angular2 Pocket Primer, LISTING 5.2: app.module.ts Listing 5.2 is straightforward: It contains two lines (​shown in bold) no binding --> <input name="fname" ngModel><! an update to the fname property in the component, thereby ensuring that the input value Third-Party UI Components Valor provides Bootstrap components for Angular, and its  I am using (ngModelChange) to push the new items to the array when the number is entered. Current behavior. When binding the item's value it is present, but for some reason the input's value is blank. Expected behavior. The input's value not to be blank. Minimal reproduction of the problem with instructions

We can also obtain its value using $event and not using ngModel-

component.html

<table>
<tbody>
<tr>
<td colspan="2" style="width:100px;height:38px;"><input type = "text"  (change)="enterDirectRowNumberResponse(data,$event.target.value)"></td></tr>
</tbody
</table>

component.ts

enterDirectRowNumberResponse(data,event){
        console.log ("Inside enterDirectRowNumberResponse",event)
        console.log ("data = ", data );
}

ngModelChange no longer working, Discussion of topic ngModelChange no longer working in General Discussion forum. JavaScript UI Controls · JavaScript Reporting · JavaScript When the value in a dropdown menu item changes, a function should be called to update that column in Is there an equivalent mechanism on wj-input-date? TodoList cannot detect this, as its input reference todos did not change; the second button does work! notice that the method addTodo() creates a copy of the todo list, and then adds an item to the copy and finally replaces the todos member variable with the copied list. This triggers change detection because the component detects a reference change in its input: it received a new list!

Optimize Angular's change detection, Change detection can be triggered either manually or through an It also includes an ngModel directive for two-way data binding between the input and the label process may block the browser's UI thread and cause frame drops, the app won't recalculate the numeric value for individual employees. click is a DOM event, not related to the higher level ngModel. The proper event for this is ngModelChange. If you want to use DOM events, then forget about ngModel and use $event inside the handler or a #ref. So, instead of. <input [ (ngModel)]="item.completed" (click)="completed (i)" type="checkbox">.

Angular Data Grid | Material Table | Ignite UI for Angular, Learn how to use Ignite UI angular data grid, based on Angular Material Table and create the value is changed in the template --> <input type="checkbox" [​ngModel]="cell.value" If the data in a cell is bound with [(ngModel)] and the value change is not handled, the The data structure specific for rendering is in the form: ng-model does not update when sending a value to an input you want to update the model your input is bound to (and let angular propagate it to the view) instead

Angular ng-change Directive, It will not wait until all changes are made, or when the input field loses focus. The ng-change event is only triggered if there is a actual change in the input value,  I'm seeing an issue in beta.1 that appears to be a regression from beta.0. ngModel/ngModelChange don't appear to work at all in Firefox, at least on selects. Here's a plunkr demo.

Comments
  • you can use (change) instead of (ngModelChange), stackoverflow.com/questions/44840735/…
  • Isn't your code resulting in an infinite loop? Because you are re-assigning to the source that is emitting an event in a handler. Or may be it won't when you re-assign the previous value.
  • @SteveRuben, Can you please explain how will that help?
  • @AmitChigadani, No it isn't goining into infinite loop. The the event triggers only when the user inputs something. In that event, the new value gets assinged. And it waits for user to update it.
  • @Yogesh, check if my answer helps.
  • Can you please tell me what was wrong with my approach?
  • @Yogesh, I'm still analyzing it. I'll let you know if I find anything substantial.
  • Please do let me know. I'm curious.
  • @SiddAjmera buy (change) can only invoke once after you trigger blur .
  • Thanks Suresh, glad to know it helped ;)
  • I would say that the main reason here is how Angular change detection mechanism works under the hood. It won't update property or trigger ngOnChanges hook if value hasn't changed. We can see it here stackblitz.com/edit/…
  • Also blur/change event will help only once. If we type 1.2 then click outside the input value will become 1, after that if we try to change the value from 1 to 1.2 and trigger blur that value won't be changed to 1. stackblitz.com/edit/angular-ngmodelchanges-eg-jvvzrs?file=src/…
  • But if we will change the value like this.model.rate = new String(Math.round(value)); then change/blur events will definitely work stackblitz.com/edit/angular-ngmodelchanges-eg-upzz5p?file=src/…
  • @PankajParkar Now I got to know why that didn't work. @yurzui Yep, the ``(change)` event also worked only once.