(ngModelChange) does not update the UI for specific input












2















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!










share|improve this question























  • you can use (change) instead of (ngModelChange), stackoverflow.com/questions/44840735/…

    – Steve Ruben
    Nov 22 '18 at 9:34













  • 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.

    – Amit Chigadani
    Nov 22 '18 at 9:40













  • @SteveRuben, Can you please explain how will that help?

    – Yogesh
    Nov 22 '18 at 9:42











  • @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
    Nov 22 '18 at 9:44











  • @Yogesh, check if my answer helps.

    – SiddAjmera
    Nov 22 '18 at 9:44
















2















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!










share|improve this question























  • you can use (change) instead of (ngModelChange), stackoverflow.com/questions/44840735/…

    – Steve Ruben
    Nov 22 '18 at 9:34













  • 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.

    – Amit Chigadani
    Nov 22 '18 at 9:40













  • @SteveRuben, Can you please explain how will that help?

    – Yogesh
    Nov 22 '18 at 9:42











  • @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
    Nov 22 '18 at 9:44











  • @Yogesh, check if my answer helps.

    – SiddAjmera
    Nov 22 '18 at 9:44














2












2








2








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!










share|improve this question














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!







angular angular2-ngmodel






share|improve this question













share|improve this question











share|improve this question




share|improve this question










asked Nov 22 '18 at 9:23









YogeshYogesh

458215




458215













  • you can use (change) instead of (ngModelChange), stackoverflow.com/questions/44840735/…

    – Steve Ruben
    Nov 22 '18 at 9:34













  • 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.

    – Amit Chigadani
    Nov 22 '18 at 9:40













  • @SteveRuben, Can you please explain how will that help?

    – Yogesh
    Nov 22 '18 at 9:42











  • @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
    Nov 22 '18 at 9:44











  • @Yogesh, check if my answer helps.

    – SiddAjmera
    Nov 22 '18 at 9:44



















  • you can use (change) instead of (ngModelChange), stackoverflow.com/questions/44840735/…

    – Steve Ruben
    Nov 22 '18 at 9:34













  • 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.

    – Amit Chigadani
    Nov 22 '18 at 9:40













  • @SteveRuben, Can you please explain how will that help?

    – Yogesh
    Nov 22 '18 at 9:42











  • @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
    Nov 22 '18 at 9:44











  • @Yogesh, check if my answer helps.

    – SiddAjmera
    Nov 22 '18 at 9:44

















you can use (change) instead of (ngModelChange), stackoverflow.com/questions/44840735/…

– Steve Ruben
Nov 22 '18 at 9:34







you can use (change) instead of (ngModelChange), stackoverflow.com/questions/44840735/…

– Steve Ruben
Nov 22 '18 at 9:34















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.

– Amit Chigadani
Nov 22 '18 at 9:40







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.

– Amit Chigadani
Nov 22 '18 at 9:40















@SteveRuben, Can you please explain how will that help?

– Yogesh
Nov 22 '18 at 9:42





@SteveRuben, Can you please explain how will that help?

– Yogesh
Nov 22 '18 at 9:42













@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
Nov 22 '18 at 9:44





@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
Nov 22 '18 at 9:44













@Yogesh, check if my answer helps.

– SiddAjmera
Nov 22 '18 at 9:44





@Yogesh, check if my answer helps.

– SiddAjmera
Nov 22 '18 at 9:44












3 Answers
3






active

oldest

votes


















1














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.






share|improve this answer


























  • Can you please tell me what was wrong with my approach?

    – Yogesh
    Nov 22 '18 at 10:18











  • @Yogesh, I'm still analyzing it. I'll let you know if I find anything substantial.

    – SiddAjmera
    Nov 22 '18 at 10:34











  • Please do let me know. I'm curious.

    – Yogesh
    Nov 22 '18 at 13:40



















3














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:



enter image description here



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






share|improve this answer


























  • Thanks Pankaj. It's a very good explanation

    – Suresh Kumar Ariya
    Nov 23 '18 at 1:46






  • 1





    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/…

    – yurzui
    Nov 23 '18 at 5:07






  • 1





    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/…

    – yurzui
    Nov 23 '18 at 5:10








  • 2





    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/…

    – yurzui
    Nov 23 '18 at 5:15








  • 1





    @PankajParkar Now I got to know why that didn't work. @yurzui Yep, the ``(change)` event also worked only once.

    – Yogesh
    Nov 23 '18 at 5:17



















0















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();





share|improve this answer























    Your Answer






    StackExchange.ifUsing("editor", function () {
    StackExchange.using("externalEditor", function () {
    StackExchange.using("snippets", function () {
    StackExchange.snippets.init();
    });
    });
    }, "code-snippets");

    StackExchange.ready(function() {
    var channelOptions = {
    tags: "".split(" "),
    id: "1"
    };
    initTagRenderer("".split(" "), "".split(" "), channelOptions);

    StackExchange.using("externalEditor", function() {
    // Have to fire editor after snippets, if snippets enabled
    if (StackExchange.settings.snippets.snippetsEnabled) {
    StackExchange.using("snippets", function() {
    createEditor();
    });
    }
    else {
    createEditor();
    }
    });

    function createEditor() {
    StackExchange.prepareEditor({
    heartbeatType: 'answer',
    autoActivateHeartbeat: false,
    convertImagesToLinks: true,
    noModals: true,
    showLowRepImageUploadWarning: true,
    reputationToPostImages: 10,
    bindNavPrevention: true,
    postfix: "",
    imageUploader: {
    brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
    contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
    allowUrls: true
    },
    onDemand: true,
    discardSelector: ".discard-answer"
    ,immediatelyShowMarkdownHelp:true
    });


    }
    });














    draft saved

    draft discarded


















    StackExchange.ready(
    function () {
    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53427571%2fngmodelchange-does-not-update-the-ui-for-specific-input%23new-answer', 'question_page');
    }
    );

    Post as a guest















    Required, but never shown

























    3 Answers
    3






    active

    oldest

    votes








    3 Answers
    3






    active

    oldest

    votes









    active

    oldest

    votes






    active

    oldest

    votes









    1














    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.






    share|improve this answer


























    • Can you please tell me what was wrong with my approach?

      – Yogesh
      Nov 22 '18 at 10:18











    • @Yogesh, I'm still analyzing it. I'll let you know if I find anything substantial.

      – SiddAjmera
      Nov 22 '18 at 10:34











    • Please do let me know. I'm curious.

      – Yogesh
      Nov 22 '18 at 13:40
















    1














    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.






    share|improve this answer


























    • Can you please tell me what was wrong with my approach?

      – Yogesh
      Nov 22 '18 at 10:18











    • @Yogesh, I'm still analyzing it. I'll let you know if I find anything substantial.

      – SiddAjmera
      Nov 22 '18 at 10:34











    • Please do let me know. I'm curious.

      – Yogesh
      Nov 22 '18 at 13:40














    1












    1








    1







    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.






    share|improve this answer















    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.







    share|improve this answer














    share|improve this answer



    share|improve this answer








    edited Nov 22 '18 at 16:24

























    answered Nov 22 '18 at 9:41









    SiddAjmeraSiddAjmera

    13.4k31137




    13.4k31137













    • Can you please tell me what was wrong with my approach?

      – Yogesh
      Nov 22 '18 at 10:18











    • @Yogesh, I'm still analyzing it. I'll let you know if I find anything substantial.

      – SiddAjmera
      Nov 22 '18 at 10:34











    • Please do let me know. I'm curious.

      – Yogesh
      Nov 22 '18 at 13:40



















    • Can you please tell me what was wrong with my approach?

      – Yogesh
      Nov 22 '18 at 10:18











    • @Yogesh, I'm still analyzing it. I'll let you know if I find anything substantial.

      – SiddAjmera
      Nov 22 '18 at 10:34











    • Please do let me know. I'm curious.

      – Yogesh
      Nov 22 '18 at 13:40

















    Can you please tell me what was wrong with my approach?

    – Yogesh
    Nov 22 '18 at 10:18





    Can you please tell me what was wrong with my approach?

    – Yogesh
    Nov 22 '18 at 10:18













    @Yogesh, I'm still analyzing it. I'll let you know if I find anything substantial.

    – SiddAjmera
    Nov 22 '18 at 10:34





    @Yogesh, I'm still analyzing it. I'll let you know if I find anything substantial.

    – SiddAjmera
    Nov 22 '18 at 10:34













    Please do let me know. I'm curious.

    – Yogesh
    Nov 22 '18 at 13:40





    Please do let me know. I'm curious.

    – Yogesh
    Nov 22 '18 at 13:40













    3














    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:



    enter image description here



    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






    share|improve this answer


























    • Thanks Pankaj. It's a very good explanation

      – Suresh Kumar Ariya
      Nov 23 '18 at 1:46






    • 1





      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/…

      – yurzui
      Nov 23 '18 at 5:07






    • 1





      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/…

      – yurzui
      Nov 23 '18 at 5:10








    • 2





      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/…

      – yurzui
      Nov 23 '18 at 5:15








    • 1





      @PankajParkar Now I got to know why that didn't work. @yurzui Yep, the ``(change)` event also worked only once.

      – Yogesh
      Nov 23 '18 at 5:17
















    3














    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:



    enter image description here



    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






    share|improve this answer


























    • Thanks Pankaj. It's a very good explanation

      – Suresh Kumar Ariya
      Nov 23 '18 at 1:46






    • 1





      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/…

      – yurzui
      Nov 23 '18 at 5:07






    • 1





      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/…

      – yurzui
      Nov 23 '18 at 5:10








    • 2





      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/…

      – yurzui
      Nov 23 '18 at 5:15








    • 1





      @PankajParkar Now I got to know why that didn't work. @yurzui Yep, the ``(change)` event also worked only once.

      – Yogesh
      Nov 23 '18 at 5:17














    3












    3








    3







    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:



    enter image description here



    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






    share|improve this answer















    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:



    enter image description here



    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







    share|improve this answer














    share|improve this answer



    share|improve this answer








    edited Nov 23 '18 at 5:52









    yurzui

    95.7k11189212




    95.7k11189212










    answered Nov 22 '18 at 19:26









    Pankaj ParkarPankaj Parkar

    112k15159234




    112k15159234













    • Thanks Pankaj. It's a very good explanation

      – Suresh Kumar Ariya
      Nov 23 '18 at 1:46






    • 1





      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/…

      – yurzui
      Nov 23 '18 at 5:07






    • 1





      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/…

      – yurzui
      Nov 23 '18 at 5:10








    • 2





      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/…

      – yurzui
      Nov 23 '18 at 5:15








    • 1





      @PankajParkar Now I got to know why that didn't work. @yurzui Yep, the ``(change)` event also worked only once.

      – Yogesh
      Nov 23 '18 at 5:17



















    • Thanks Pankaj. It's a very good explanation

      – Suresh Kumar Ariya
      Nov 23 '18 at 1:46






    • 1





      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/…

      – yurzui
      Nov 23 '18 at 5:07






    • 1





      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/…

      – yurzui
      Nov 23 '18 at 5:10








    • 2





      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/…

      – yurzui
      Nov 23 '18 at 5:15








    • 1





      @PankajParkar Now I got to know why that didn't work. @yurzui Yep, the ``(change)` event also worked only once.

      – Yogesh
      Nov 23 '18 at 5:17

















    Thanks Pankaj. It's a very good explanation

    – Suresh Kumar Ariya
    Nov 23 '18 at 1:46





    Thanks Pankaj. It's a very good explanation

    – Suresh Kumar Ariya
    Nov 23 '18 at 1:46




    1




    1





    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/…

    – yurzui
    Nov 23 '18 at 5:07





    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/…

    – yurzui
    Nov 23 '18 at 5:07




    1




    1





    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/…

    – yurzui
    Nov 23 '18 at 5:10







    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/…

    – yurzui
    Nov 23 '18 at 5:10






    2




    2





    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/…

    – yurzui
    Nov 23 '18 at 5:15







    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/…

    – yurzui
    Nov 23 '18 at 5:15






    1




    1





    @PankajParkar Now I got to know why that didn't work. @yurzui Yep, the ``(change)` event also worked only once.

    – Yogesh
    Nov 23 '18 at 5:17





    @PankajParkar Now I got to know why that didn't work. @yurzui Yep, the ``(change)` event also worked only once.

    – Yogesh
    Nov 23 '18 at 5:17











    0















    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();





    share|improve this answer




























      0















      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();





      share|improve this answer


























        0












        0








        0








        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();





        share|improve this answer














        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();






        share|improve this answer












        share|improve this answer



        share|improve this answer










        answered Nov 22 '18 at 9:31









        Sanjay KatiyarSanjay Katiyar

        39518




        39518






























            draft saved

            draft discarded




















































            Thanks for contributing an answer to Stack Overflow!


            • Please be sure to answer the question. Provide details and share your research!

            But avoid



            • Asking for help, clarification, or responding to other answers.

            • Making statements based on opinion; back them up with references or personal experience.


            To learn more, see our tips on writing great answers.




            draft saved


            draft discarded














            StackExchange.ready(
            function () {
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53427571%2fngmodelchange-does-not-update-the-ui-for-specific-input%23new-answer', 'question_page');
            }
            );

            Post as a guest















            Required, but never shown





















































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown

































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown







            Popular posts from this blog

            404 Error Contact Form 7 ajax form submitting

            How to know if a Active Directory user can login interactively

            TypeError: fit_transform() missing 1 required positional argument: 'X'