(ngModelChange) does not update the UI for specific 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!
angular angular2-ngmodel
|
show 4 more comments
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
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
|
show 4 more comments
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
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
angular angular2-ngmodel
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
|
show 4 more comments
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
|
show 4 more comments
3 Answers
3
active
oldest
votes
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.
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
add a comment |
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
.
- type
1
=> model.rate becomes1
- type
1.
=> model.rate stays1
- type
1.1
=> model.rate stays1
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
- type
4
=> model.rate becomes4
- type
4.
=> model.rate stays4
- type
4.6
=> model.rate becomes5
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
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 likethis.model.rate = new String(Math.round(value));
thenchange/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
|
show 3 more comments
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();
add a comment |
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
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
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
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.
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
add a comment |
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.
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
add a comment |
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.
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.
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
add a comment |
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
add a comment |
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
.
- type
1
=> model.rate becomes1
- type
1.
=> model.rate stays1
- type
1.1
=> model.rate stays1
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
- type
4
=> model.rate becomes4
- type
4.
=> model.rate stays4
- type
4.6
=> model.rate becomes5
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
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 likethis.model.rate = new String(Math.round(value));
thenchange/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
|
show 3 more comments
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
.
- type
1
=> model.rate becomes1
- type
1.
=> model.rate stays1
- type
1.1
=> model.rate stays1
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
- type
4
=> model.rate becomes4
- type
4.
=> model.rate stays4
- type
4.6
=> model.rate becomes5
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
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 likethis.model.rate = new String(Math.round(value));
thenchange/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
|
show 3 more comments
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
.
- type
1
=> model.rate becomes1
- type
1.
=> model.rate stays1
- type
1.1
=> model.rate stays1
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
- type
4
=> model.rate becomes4
- type
4.
=> model.rate stays4
- type
4.6
=> model.rate becomes5
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
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
.
- type
1
=> model.rate becomes1
- type
1.
=> model.rate stays1
- type
1.1
=> model.rate stays1
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
- type
4
=> model.rate becomes4
- type
4.
=> model.rate stays4
- type
4.6
=> model.rate becomes5
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
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 likethis.model.rate = new String(Math.round(value));
thenchange/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
|
show 3 more comments
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 likethis.model.rate = new String(Math.round(value));
thenchange/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
|
show 3 more comments
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();
add a comment |
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();
add a comment |
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();
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();
answered Nov 22 '18 at 9:31
Sanjay KatiyarSanjay Katiyar
39518
39518
add a comment |
add a comment |
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.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
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
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
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
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