Skip to content

fix(forms): ensure to emit status change events on subsequent value-update / validations - #20806

Closed
kgopi wants to merge 1 commit into
angular:masterfrom
kgopi:20424
Closed

kgopi wants to merge 1 commit into
angular:masterfrom
kgopi:20424

Conversation

@kgopi

@kgopi kgopi commented Dec 5, 2017 •

Copy link
Copy Markdown

fix(forms): ensure to emit status change events on subsequent value-update / validations

RCA:

During initialization of FormControl, emitEvent is getting passed as false to updateValueAndValidity function, in turn the same value got passed to the _runAsyncValidator function. (sets status = 'PENDING') and asyncValidator will be invoked.
When we set the FormControl to the FormGroup via FormGroup.setcontrol, internally it is calling updateValueAndValidity (on FormGroup) function with emitEvent as undefined, it causes status change event to be emitted on FormGroup instance. (causes 'PENDING' status change event)
When the asyncValidator (of FormControl) got resolved, setErrors function is getting invoked by passing the lexical scoped variable emitEvent (false in this case).
As emitEvent value is false, susbsequent status change events are not getting notified !!

If I understand correctly, status-change-events needs to be notified on value update / validations.

Please correct me, If I am wrong.

Issue: #20424

PR Checklist

Please check if your PR fulfills the following requirements:

PR Type

What kind of change does this PR introduce?

[x] Bugfix
[ ] Feature
[ ] Code style update (formatting, local variables)
[ ] Refactoring (no functional changes, no api changes)
[ ] Build related changes
[ ] CI related changes
[ ] Documentation content changes
[ ] angular.io application / infrastructure changes
[ ] Other... Please describe:

What is the current behavior?

Issue Number: #20424

What is the new behavior?

Does this PR introduce a breaking change?

[ ] Yes
[x] No

Other information

@suspectpart

suspectpart commented Dec 11, 2019 •

Copy link
Copy Markdown

@mprobst

mprobst commented Dec 11, 2019

Copy link
Copy Markdown
Contributor

@suspectpart: please don't spam.

@suspectpart

Copy link
Copy Markdown

@suspectpart: please don't spam.

I am sorry for spamming you, not the best way for sure. I just didn't know who in the list of reviewers is still active and could provide some feedback. My apologies.

@JasonRammoray

JasonRammoray commented Jan 7, 2020 •

Copy link
Copy Markdown

Having in mind the fact that everyone is quite busy, one can't help but notice this is quite a severe issue especially in cases when a form control is being encapsulated within a container with *ngIf structural directive that changes its value depending on a context.
To prove it's true, here is a simple demo (Angular 8) proving the issue is still there.
It's been a while now since the fix has been prepared for more than two years.
What shall be done in order to merge it with the master branch?
Thanks.

Comment thread packages/forms/src/model.ts Outdated

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure what others think, but I would be tempted to make this shorter by using !!asyncValidator.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd prefer shorter version as well 👍

@petebacondarwin petebacondarwin self-assigned this Jan 8, 2020
…pdate / validations

RCA:

During initialization of FormControl, `emitEvent` is getting passed as `false` to `updateValueAndValidity` function, inturn the same value got passed to the `_runAsyncValidator` function. (sets status = 'PENDING') and asyncValidator will be invoked.
When we set the `FormControl` to the `FormGroup` via `FormGroup.setcontrol`, internally it is calling `updateValueAndValidity` (on FormGroup) function with `emitEvent` as undefined, it causes status change event to be emitted on `FormGroup` instance. (causes 'PENDING' status change event)
When the asyncValidator (of FormControl) got resolved, `setErrors` function is getting invoked by passing the lexical scoped variable `emitEvent` (false in this case).
As emitEvent value is `false`, susbsequent status change events are not getting notified !!

If I understand correctly, status-change-events needs to be notified on value update / validations.

Please correct me, If I am wrong.

Issue: angular#20424
@petebacondarwin

Copy link
Copy Markdown
Contributor

Rebased on master...

@petebacondarwin

Copy link
Copy Markdown
Contributor

To land this we need a presubmit from a Googler, and a review from someone in the angular/fw-forms code owner group.

@petebacondarwin petebacondarwin removed their assignment Jan 8, 2020
@petebacondarwin petebacondarwin added the action: presubmit The PR is in need of a google3 presubmit label Jan 8, 2020
@AndrewKushnir

Copy link
Copy Markdown
Contributor

Presubmit

@AndrewKushnir

Copy link
Copy Markdown
Contributor

Hi @kgopi, after running google3 tests, it turned out that this change breaks a few targets and additional investigation is required to find the origin of these failures and perform the necessary adjustments (either in the changes in this PR or in google3 apps code). I added the "blocked" label for now to indicate that and we'll get back to this PR once v9 final is released. Thank you.

@suspectpart

Copy link
Copy Markdown

Hi @kgopi, after running google3 tests, it turned out that this change breaks a few targets and additional investigation is required to find the origin of these failures and perform the necessary adjustments (either in the changes in this PR or in google3 apps code). I added the "blocked" label for now to indicate that and we'll get back to this PR once v9 final is released. Thank you.

Can you give a rough projection when this is gonna happen? Is it more like a few weeks or a couple of months?

@AndrewKushnir

Copy link
Copy Markdown
Contributor

Can you give a rough projection when this is gonna happen? Is it more like a few weeks or a couple of months?

Hi @suspectpart, I can not provide any ETA at this moment unfortunately, since ETA also depends on post v9 prioritization. I've added this ticket to "v10-candidates" milestone, so it will be reviewed and prioritized after v9 is released. Thank you.

@JasonRammoray

JasonRammoray commented Feb 21, 2020 •

Copy link
Copy Markdown

I added the "blocked" label for now to indicate that and we'll get back to this PR once v9 final is released.

@AndrewKushnir, the 9th version has been rolled out recently.
Could you, please, shed some light on google3 tests failure investigation process?
Thanks.

@estankovic

Copy link
Copy Markdown

Any updates on this one? It have been a while since v9 rolled out

this.updateValueAndValidity({
onlySelf: true,
emitEvent: asyncValidator ? true : false
}); // `asyncValidator` will cause status change, and that needs to be notified

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd propose moving the comment above the corresponding line + use !!asyncValidator as Pete proposed, something like this (I've also updated a comment a bit):

this.updateValueAndValidity({
  onlySelf: true,
  // If `asyncValidator` is present, it will trigger control status change from `PENDING` to `VALID` or `INVALID`.
  // The status should be broadcasted via the `statusChanges` observable, so we set `emitEvent` to `true`
  // to allow that during the control creation process.
  emitEvent: !!asyncValidator
});

The same/similar comment can be added to other places as well (FormGroup and FormArray).

expect(logger).toEqual(['change!']);
});

it('should only emit (`VALID`) status change event in absence of `FormControl.asyncValidator`',

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for adding tests 👍

I think we should increase test coverage a bit more to handle additional cases, for example:

  • Standalone FormControl with async validator and both statusChanges and valueChanges subscriptions and log what the output is. We should have 2 tests here tp cover both VALID and INVALID results of the validation.

  • Standalone FormControl with both sync and async validators and see what happens in statusChanges and valueChanges subscriptions when sync validators return true/false and async validator returns true/false.

  • Combination of FormGroup and a child FormControl to test the behavior when we initialize such combination and:

    • async validator is present on a FormControl level
    • async validator is present on both FormGroup and a child FormControl level
  • Similar to the previous item, but cover the setControl case (this is what is partially implemented already).

  • Similar to the one above, the combination of FormArray and a child FormControl: initialization phase and a case with calling some API methods that might trigger status change (like pushing new controls to the array).

  • Combination of all classes: FormGroup, FormArray (as a child to the FormGroup) and FormControl (as a child to FormArray).

Once we have improved coverage, we can also see what the difference is in what we emit into the statusChanges and valueChanges now vs what the new set of events are. That should help better formalize the "breaking changes" note to let developers know which changes to expect and how to handle them (if needed).

Please let me know if any additional information is required.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Quick comment to the previous one: I think it'd also be great to have a test that would replace/remove a control (via setControl and/or other methods) which is running an async validator at this moment (i.e. in PENDING state), to see which events would be emitted in statusChanges.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, one more comment: it looks like PR #22575 might also be related to your PR, since it fixes the problem with async validation status, so you may see some incorrect results (described in #22575) in the statusChanges log until #22575 is accepted/merged.

@AndrewKushnir

Copy link
Copy Markdown
Contributor

Hi @kgopi, sorry for the delay in answering.

I've re-ran presubmit and it looks like there is a couple places where this change triggering some failures. I will perform additional investigation and let you know.

I also had a look at the changes and posted additional comments, mostly related to proposed increase in test coverage. Please let me know if you have any questions/comments.

Thank you.

@AndrewKushnir

Copy link
Copy Markdown
Contributor

Hi @kgopi,

Just want to give a quick update: the PR #22575 that I mentioned (with the fixes to the control status with async validators) has landed recently (so you should have more accurate control status in tests now). Also I've updated a couple apps in Google's codebase to be compatible with this change.

If you have a chance to perform additional updates based on the comments above (and add tests as I mentioned in #20806 (comment)), please let us know.

Thank you.

@sonukapoor sonukapoor self-assigned this Jul 25, 2020
@AndrewKushnir AndrewKushnir removed the action: presubmit The PR is in need of a google3 presubmit label Aug 25, 2020
@AndrewKushnir

Copy link
Copy Markdown
Contributor

Hi @kgopi, thanks for working on this issue and proposing the fix. FYI, similar change was made in #38354, so I'm closing this PR in favor of #38354. Thank you.

@angular-automatic-lock-bot

Copy link
Copy Markdown

This issue has been automatically locked due to inactivity.
Please file a new issue if you are encountering a similar or related problem.

Read more about our automatic conversation locking policy.

This action has been performed automatically by a bot.

@angular-automatic-lock-bot angular-automatic-lock-bot Bot locked and limited conversation to collaborators Sep 28, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.