You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
ngmodelOptions.updateon: 'blur' and input onblur event updating model value only for the first time #30653
I have a textbox which has ngModel, ngModelOptions(updateOn: 'blur') and it has onblur event handler. Now i am validating input value on blur event callback and if the value is less than 100 i will show error message and i will empty the text box value.
Issue: If I enter the value lessthan 100 then the textbox value is clearing properly only for the first time. From second time onwards the value is not emptied.
for example: enter 12 in input box and blur the input box we are getting the error message and it is lessthan 100 so value is set to empty(""). Now, i remove the 12 in input box and entered 55 this time the error message is showing up but the value is not clearing. It is showing the previous value.
Note: I tried to trigger angular change detection(detechChanges()) on blur event(after setting value to empty) even though the value is not clearing second time onwards.
I'm not 100% up to speed with Angular's internals so i might be not completely correct in my explanation.
When the user writes a number lesser than 100, you are resetting the value to "", if at this point the user writes again a number lesser than 100, the variable changes to, say, 20, but then gets instantly reset to "".
This means that during Angular's CD you will always have a check like "" != "" for consecutive lesser-than-100 numbers.
To fix this, you have to "give Angular time" to process the previous input, and only after that you can assign the new, empty value.
This "give Angular time" translates to waiting the javascript stack to be executed and only then reset your input. Which in turn means that your line
this.datavalue = "";
needs to be changed to
setTimeout(()=>{this.datavalue = ""});
I've been using Angular for a couple years now and trust me, sooner or later, you'll spam "setTimeout"s everywhere
@jasonaden I have encountered this issue since Angular 2.0 to be honest... my entire application is built around feeding Angular's change detection with the right data at the right time.
If this is actually an Angular's bug that's gonna be pretty big
As mentioned previously, the reason is probably that the same event (the blur event) is used to trigger an update of the value of the "AppComponent.datavalue" (the variable associated with the NgModel directive).
These 2 updates are done by :
the NgModel directive (operation 1)
the callback handleChange() (operation 2)
Only after these 2 operations, the Change detector will compare the "AppComponent.datavalue" values before and after the event. If there is a change, it will update the new value in the template. The problem is that sometimes (actually when user enters twice a number < 100), operation 2 cancels the change which was made by operation 1
=> the change detector doesn't see any change and doesn't update the template.
Therefore the change detector has to be called between operation 1 and operation 2 (I could not format code but there is a link to a demo after):
handleChange(event) { // The ngModel directive already updated the datavalue variable // = operation 1 is done if (this.datavalue < 100) { this.msg = 'please enter the value greaterthan 100'; // we call the change detector before the operation 2 this.cd.detectChanges(); // operation 2 this.datavalue = ""; } else { this.msg = ""; } } }
Nb: the first time the user enters a value in the input is always working because, even if operation 2 may remove the user's value (if value < 100), it actually defines the variable "AppComponent.datavalue" and assign it the value "", so there is a detectable change.
Activity
EmaGht commentedon May 27, 2019
I'm not 100% up to speed with Angular's internals so i might be not completely correct in my explanation.
When the user writes a number lesser than 100, you are resetting the value to "", if at this point the user writes again a number lesser than 100, the variable changes to, say, 20, but then gets instantly reset to "".
This means that during Angular's CD you will always have a check like "" != "" for consecutive lesser-than-100 numbers.
To fix this, you have to "give Angular time" to process the previous input, and only after that you can assign the new, empty value.
This "give Angular time" translates to waiting the javascript stack to be executed and only then reset your input. Which in turn means that your line
this.datavalue = "";needs to be changed to
setTimeout(()=>{this.datavalue = ""});I've been using Angular for a couple years now and trust me, sooner or later, you'll spam "setTimeout"s everywhere
jasonaden commentedon May 28, 2019
Just playing with the example, if you change to a value that is greater than 100, then back to a value under 100, it works again.
Thanks for the issue. There seems to be odd behavior with change detection here. Yes, the solution above does work, but shouldn't be required.
EmaGht commentedon May 29, 2019
@jasonaden I have encountered this issue since Angular 2.0 to be honest... my entire application is built around feeding Angular's change detection with the right data at the right time.
If this is actually an Angular's bug that's gonna be pretty big
ElisePatrikainen commentedon Jul 10, 2019
As mentioned previously, the reason is probably that the same event (the blur event) is used to trigger an update of the value of the "AppComponent.datavalue" (the variable associated with the NgModel directive).
These 2 updates are done by :
Only after these 2 operations, the Change detector will compare the "AppComponent.datavalue" values before and after the event. If there is a change, it will update the new value in the template. The problem is that sometimes (actually when user enters twice a number < 100), operation 2 cancels the change which was made by operation 1
=> the change detector doesn't see any change and doesn't update the template.
Therefore the change detector has to be called between operation 1 and operation 2 (I could not format code but there is a link to a demo after):
handleChange(event) { // The ngModel directive already updated the datavalue variable // = operation 1 is done if (this.datavalue < 100) { this.msg = 'please enter the value greaterthan 100'; // we call the change detector before the operation 2 this.cd.detectChanges(); // operation 2 this.datavalue = ""; } else { this.msg = ""; } } }Here is the code demo : https://stackblitz.com/edit/angular-1aldzw
Nb: the first time the user enters a value in the input is always working because, even if operation 2 may remove the user's value (if value < 100), it actually defines the variable "AppComponent.datavalue" and assign it the value "", so there is a detectable change.
Ajay070792 commentedon Jul 7, 2020
@ElisePatrikainen solution is not working for me. Is there any other solutions to this problem?
Thanks in advance.
mgohin commentedon Nov 19, 2021
Calling the
this.cd.detectChanges();before setting the new value in my form did work for me. Thanks !May I suggest @ElisePatrikainen that you use a code block in your answer so it'll be more pleasant to read :)