Skip to content
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

AbstractControl constructed with an array of validators mutates the original array on control.addValidators() #47827

Closed
idpaterson opened this issue Oct 20, 2022 · 2 comments
Assignees
Labels
area: forms forms: validators P3 An issue that is relevant to core functions, but does not impede progress. Important, but not urgent state: has PR
Milestone

Comments

@idpaterson
Copy link

idpaterson commented Oct 20, 2022

Which @angular/* package(s) are the source of the bug?

forms

Is this a regression?

No

Description

The AbstractControl constructor accepts an array of validators but methods like addValidator modify that array. When the array of validators is meant to be shared between forms as in export const PHONE_VALIDATORS: ValidationFn[] = [...], validators dynamically added to individual controls make their way into that shared array.

Please provide a link to a minimal reproduction of the bug

https://stackblitz.com/edit/angular-ivy-ud7zdz?file=src/app/form1.component.ts

Please provide the exception or error you saw

Please follow the instructions in the StackBlitz demo. Two components each use the CONSTANT_VALIDATORS export, but form 1 also uses AbstractControl.addValidators to apply additional validation to its control. This third validator is unexpectedly pushed into CONSTANT_VALIDATORS so form 2 has 3 validation rules rather than the expected 2.

The expectation is that constructing an AbstractControl with an array of validators would create a shallow copy of the array that can be modified safely.

Please provide the environment you discovered this bug in (run ng version)

Angular CLI: 14.1.0
Node: 16.18.0
Package Manager: npm 8.19.2
OS: darwin x64

Angular: 14.1.0
... animations, cli, common, compiler, compiler-cli, core, forms
... google-maps, localize, platform-browser
... platform-browser-dynamic, platform-server, router
... youtube-player

Package                         Version
---------------------------------------------------------
@angular-devkit/architect       0.1401.0
@angular-devkit/build-angular   14.1.0
@angular-devkit/core            14.1.0
@angular-devkit/schematics      14.1.0
@schematics/angular             14.1.0
rxjs                            7.5.6
typescript                      4.7.4
webpack                         5.74.0

Anything else?

In our app a "required" validator is added or removed from controls depending on whether they are visible on the screen. This allows us to mark controls that are permission controlled as required via template driven markup such that they are not required for users without permission to view the control or in any other case where the control is not rendered.

We also use FormBuilder and many forms include controls that are shared from constant (or so we thought) FormBuilder configs. For example, fb.group({ name: null, age: null, ...UserProfileFormGroupConfig }) where individual controls within UserProfileFormGroupConfig may have an array of validators.

When these two things are combined we end up with the conditional required validator getting pushed into UserProfileFormGroupConfig control validator arrays and stuck there. Forms are marked invalid because of controls that are in the FormGroup but not on the screen because they inherited this required validator.

Our workaround was to refactor the form group config as a function that returns a new config every time to avoid constants. For cases where we were using a shared array of validators like in the StackBlitz example we made sure that the AbstractControl constructor received a spread copy rather than the original array.

@ngbot ngbot bot modified the milestone: needsTriage Oct 20, 2022
@crisbeto crisbeto self-assigned this Oct 21, 2022
crisbeto added a commit to crisbeto/angular that referenced this issue Oct 21, 2022
Fixes that the `AbstractControl` was mutating the validators arrays being passed into the constructor an helper methods like `setValidators`.

Fixes angular#47827.
crisbeto added a commit to crisbeto/angular that referenced this issue Oct 21, 2022
Fixes that the `AbstractControl` was mutating the validators arrays being passed into the constructor an helper methods like `setValidators`.

Fixes angular#47827.
pkozlowski-opensource pushed a commit that referenced this issue Oct 24, 2022
Fixes that the `AbstractControl` was mutating the validators arrays being passed into the constructor an helper methods like `setValidators`.

Fixes #47827.

PR Close #47830
@pkozlowski-opensource
Copy link
Member

Re-opening this issue as the fix PR #47830 will be reverted via #47845

nouraellm pushed a commit to nouraellm/angular that referenced this issue Nov 6, 2022
Fixes that the `AbstractControl` was mutating the validators arrays being passed into the constructor an helper methods like `setValidators`.

Fixes angular#47827.

PR Close angular#47830
crisbeto added a commit to crisbeto/angular that referenced this issue Nov 16, 2022
Fixes that the `AbstractControl` was mutating the validators arrays being passed into the constructor an helper methods like `setValidators`.

Fixes angular#47827.
@alxhub alxhub added the P3 An issue that is relevant to core functions, but does not impede progress. Important, but not urgent label Nov 16, 2022
@ngbot ngbot bot modified the milestones: needsTriage, Backlog Nov 16, 2022
dylhunn pushed a commit that referenced this issue Nov 17, 2022
Fixes that the `AbstractControl` was mutating the validators arrays being passed into the constructor an helper methods like `setValidators`.

Fixes #47827.

PR Close #47830
@angular-automatic-lock-bot
Copy link

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 Dec 18, 2022
trekladyone pushed a commit to trekladyone/angular that referenced this issue Feb 1, 2023
Fixes that the `AbstractControl` was mutating the validators arrays being passed into the constructor an helper methods like `setValidators`.

Fixes angular#47827.

PR Close angular#47830
trekladyone pushed a commit to trekladyone/angular that referenced this issue Feb 1, 2023
Fixes that the `AbstractControl` was mutating the validators arrays being passed into the constructor an helper methods like `setValidators`.

Fixes angular#47827.

PR Close angular#47830
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
area: forms forms: validators P3 An issue that is relevant to core functions, but does not impede progress. Important, but not urgent state: has PR
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants