-
Notifications
You must be signed in to change notification settings - Fork 26.2k
Order of ngModel & onModelChange #11234
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
@ObaidUrRehman so this is an interesting one! To fully understand what is going on here we need to observe that So if we de-sugar your code we would end up with: If you inspect the above code you will notice that we end up with 2 We could potentially sort event handlers in the way that sugared one is executed first so I will mark it as a "bug" but don't expect it to be fixed in priority. Anyway, I think that in your case you are after having the latest (changed) model value in your |
I found the same. But there is no any description or note about order ngModel and ngModelChange in the documentation! Or! One year it's not fixed yet. Strange, very strange |
In addition, ngModelChange fires before the form is marked as dirty. This means any subsequent check for a dirty form done in the same thread, will NOT regard the form as dirty. |
At least some form of this bug still lives on, #21514 did not change the fact that the order of Tested in latest Angular |
The bug is still here in version |
The bug is still here in version 9.0.0-rc.8 |
This bug is still here in version |
In the original plunker is not that noticeable the issue, here is a reproduction on Angular 9, that affects filtering: https://angular-u3dg2n.stackblitz.io |
This bug caused me a massive headache today. Please fix it, 2020 is bad enough already. |
As @pkozlowski-opensource points out, outputs have to be executed in some order. Template order seems reasonable to me as a default ordering scheme, but I would be curious to hear more thoughts. Are you expecting something like alphabetical order? It's worth noting that the best practice for |
@kara I think the issue is not about the expected order, probably most of us were not aware of the de-sugaring, however adding to the confusion some IDEs(PHPStorm) as part of the code cleaning would move The use case here is not to set Ideally the de-sugaring would make sure that there's no duplicated |
Ouch, I didn't realize that was happening. I can see how that would cause problems.
That's an interesting idea. We probably wouldn't want to special case the compiler for |
Just experienced this issue, and wasn't aware of the ordering being important. I understand the rationale behind the current behavior, and how it might be challenging to fix cleanly. I think better documentation could help some people out. We essentially need a note (probably in the NgModel API docs) that reminds people about the de-sugaring, and that the order matters. I also think it would be best if order did not matter at all. Not sure what the best way to achieve that would be, but it would clear up a lot of confusion and unexplained behavior. |
Just had the same issue, changing the order did fix it ! This is one of the interesting bugs in Angular ! |
@SherifNeamatalla There is a long story about that topic. Some versions ago, the order was exactly the opposite, but there were other good reasons why the change was done. So it's not a bug, It was controlled change. |
2016~~2020?!Why not resolved? |
If this behaviour will change in the future, please mark it as a breaking change because i think i am not the only one relying on the order of execution to oldValue (ngModel) vs newValue ($event) to mock the old $scope.$watch in angularJS |
Same issue here. Any progress? |
hey, I haven't written angular for 1 year so I can't really remember the exact order, but I remember that one had to come before the other or else it breaks |
Guys, there's class FormControl<TValue = any> extends AbstractControl<TValue> {
new (): FormControl<any>
defaultValue: TValue
setValue(value: TValue, options?: { onlySelf?: boolean; emitEvent?: boolean; emitModelToViewChange?: boolean; emitViewToModelChange?: boolean; }): void
patchValue(value: TValue, options?: { onlySelf?: boolean; emitEvent?: boolean; emitModelToViewChange?: boolean; emitViewToModelChange?: boolean; }): void
reset(formState?: TValue | FormControlState<TValue>, options?: { onlySelf?: boolean; emitEvent?: boolean; }): void
getRawValue(): TValue
registerOnChange(fn: Function): void
registerOnDisabledChange(fn: (isDisabled: boolean) => void): void
// inherited from forms/AbstractControl
constructor(validators: ValidatorFn | ValidatorFn[], asyncValidators: AsyncValidatorFn | AsyncValidatorFn[])
value: TValue
validator: ValidatorFn | null
asyncValidator: AsyncValidatorFn | null
parent: FormGroup | FormArray | null
status: FormControlStatus
valid: boolean
invalid: boolean
pending: boolean
disabled: boolean
enabled: boolean
errors: ValidationErrors | null
pristine: boolean
dirty: boolean
touched: boolean
untouched: boolean
valueChanges: Observable<TValue>
statusChanges: Observable<FormControlStatus>
updateOn: FormHooks
root: AbstractControl
setValidators(validators: ValidatorFn | ValidatorFn[]): void
setAsyncValidators(validators: AsyncValidatorFn | AsyncValidatorFn[]): void
addValidators(validators: ValidatorFn | ValidatorFn[]): void
addAsyncValidators(validators: AsyncValidatorFn | AsyncValidatorFn[]): void
removeValidators(validators: ValidatorFn | ValidatorFn[]): void
removeAsyncValidators(validators: AsyncValidatorFn | AsyncValidatorFn[]): void
hasValidator(validator: ValidatorFn): boolean
hasAsyncValidator(validator: AsyncValidatorFn): boolean
clearValidators(): void
clearAsyncValidators(): void
markAsTouched(opts: { onlySelf?: boolean; } = {}): void
markAllAsTouched(): void
markAsUntouched(opts: { onlySelf?: boolean; } = {}): void
markAsDirty(opts: { onlySelf?: boolean; } = {}): void
markAsPristine(opts: { onlySelf?: boolean; } = {}): void
markAsPending(opts: { onlySelf?: boolean; emitEvent?: boolean; } = {}): void
disable(opts: { onlySelf?: boolean; emitEvent?: boolean; } = {}): void
enable(opts: { onlySelf?: boolean; emitEvent?: boolean; } = {}): void
setParent(parent: FormGroup<any> | FormArray<any>): void
abstract setValue(value: TRawValue, options?: Object): void
abstract patchValue(value: TValue, options?: Object): void
abstract reset(value?: TValue, options?: Object): void
getRawValue(): any
updateValueAndValidity(opts: { onlySelf?: boolean; emitEvent?: boolean; } = {}): void
setErrors(errors: ValidationErrors, opts: { emitEvent?: boolean; } = {}): void
get<P extends string | ((string | number)[])>(path: P): AbstractControl<ɵGetProperty<TRawValue, P>> | null
getError(errorCode: string, path?: string | (string | number)[]): any
hasError(errorCode: string, path?: string | (string | number)[]): boolean
} I kid 😋! Try to use this instead as much as possible. |
Faced this issue today not sure why this is not fixed yet, now I think will just use value from event instead of depending on order. |
Is weird that order affects the behavior, but there is another problem... when you autoreformat code in IDE like intelliJ ngModel is moved after ngModelChange. i hope Jetbrains Will fix this https://youtrack.jetbrains.com/issue/IDEA-347524/Angular-Plugin-reformat-ngModel |
I'm submitting a ... (check one with "x")
Current behavior
Currently the order of
(ngModelChange)
and[(ngModel)]
on an input element matters. In the following case thengModelChange
callback is called beforengModel
updates the value of model:The following however works fine:
Expected/desired behavior
Not sure what the expected behavior should be or if this the intended behavior. But I think the order of attributes in an element should not matter.
Reproduction of the problem
Link to plunker: http://plnkr.co/edit/wrVrHYx3pPdLmCKz17RL?p=preview
Open up the console and select Hero name from the drop-down. Notice how the values are printed in console. Swap the order of
ngModel
andonModelChange
and observe the difference.The text was updated successfully, but these errors were encountered: