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

feat(Forms) Expose FormControl errors to parent FormGroup #10530

Open
mhamel06 opened this issue Aug 5, 2016 · 28 comments
Open

feat(Forms) Expose FormControl errors to parent FormGroup #10530

mhamel06 opened this issue Aug 5, 2016 · 28 comments
Labels
area: forms feature: under consideration Feature request for which voting has completed and the request is now under consideration feature Issue that requests a new feature freq3: high state: Needs Design
Milestone

Comments

@mhamel06
Copy link

mhamel06 commented Aug 5, 2016

I'm submitting a ... (check one with "x")

[ ] bug report
[x feature request
[ ] support request => Please do not submit support request here, instead see https://github.com/angular/angular/blob/master/CONTRIBUTING.md#question

Current behavior
When there are errors in a form group, the formGroup.status is 'INVALID' but the formGroup.errors property is null.

ex.

formGroup.controls.username.errors: {invalidEmail: true}
formGroup.errors: null

Expected/desired behavior
When the validity of a FormControl changes, have the parent FormGroup.errors merged with the errors from the controls. This is similar to how the angularjs formController.$error property works.
https://docs.angularjs.org/api/ng/type/form.FormController

What is the motivation / use case for changing the behavior?
This would be helpful because I prefer to only disable a submit button when specific errors are on a form, such as required. With this I could drive that attribute off the formControl.errors value instead of formControl.status.

ex.

From:
<button [disabled]="myForm.status !== 'VALID'">Submit</button>

To: 
<button [disabled]="myForm.errors.required">Submit</button>
@trakhimenok
Copy link

How to distinguish group errors from control errors?

For example we can have 2 controls that are both valid but produce invalid combination. I may want to distinguish such errors from control level errors.

@0cv
Copy link

0cv commented Oct 6, 2016

Other use case is that on a large form, with potentially tabs (which hides visually errors), it becomes unclear why a form is invalid and we might have to go through each tab to tackle the error. Hence having a summary of the errors at the top form level helps a lot making the form valid.

@mhamel06
Copy link
Author

mhamel06 commented Oct 6, 2016

Along with what @Krisa mentioned, having that summary of errors easily available is nice when trying to log common problems users encounter via analytics.

@manklu
Copy link

manklu commented Oct 6, 2016

@Krisa
Create a form group for each tab. Based on the group's validity, you can provide hints about which tab contains errors. No need for details.

@0cv
Copy link

0cv commented Oct 7, 2016

@manklu That would work for something very simple. But in my case, the tabs are actually "dynamic", in the sense it's placed within a FormArray of unknown length, and there can even be tabs of tabs, or FormArray of FormArray. So at the end, it's just one massive form where I need to have a "summary" of all errors.

@fxck
Copy link

fxck commented Oct 18, 2016

Got the same problem. It's extremely confusing, I understand the need of distinguishing group errors, but there could be and extra property containing all the child errors.. that would help.

Same for status, if there's any child pending, the parent group should know about it.

@kemsky
Copy link

kemsky commented May 13, 2017

Well... once again creating wrapper directive...

@smartm0use
Copy link
Contributor

smartm0use commented Jun 16, 2017

+1 for this feature request.

@geo242
Copy link

geo242 commented Jul 28, 2017

+1

@mko
Copy link

mko commented Oct 23, 2017

Has there been any consideration on picking this up? I'd expect a lot of people working with complex forms are creating workarounds for this like we had to, effectively creating methods that recursively traverse the tree of controls looking at each control's errors objects manually in order to create an aggregate object.

@benneq
Copy link

benneq commented Mar 26, 2018

I came across the same problem. But it's not the first issue I have with forms...

I was really excited when reactive forms were released. But the more you use it in real world applications the more issues I encountered.

Is there some issue which contains all the current problems / feature requests / improvements for the forms module?

What I collected the last days:

@NatoBoram
Copy link

I stumbled upon the duplicate #11530 from Google and...

Yeah, I can't believe this isn't a thing. I think that any way of implementing it would've been better than the current nothing, even if we don't have a way to track back to the original invalid control.

@maxime1992
Copy link

maxime1992 commented Jun 14, 2019

It'd definitely be a nice thing to have that included in Angular itself.

In the meantime, we've created at work an open source library called ngx-sub-form (available here: https://github.com/cloudnc/ngx-sub-form) to be able to split our huge forms into smaller forms/components. One of the good part that is related to this thread? 😃

We do have access to all the nested errors 🎉

Example with that form, where Droid form and Assassin form are sub components:

image

And the errors that are accessible from the top level form component:

image

If you're interested, you can find the live demo here: https://cloudnc.github.io/ngx-sub-form

And the source code of the demo here: https://github.com/cloudnc/ngx-sub-form/tree/master/src/app

I think that any way of implementing it would've been better than the current nothing, even if we don't have a way to track back to the original invalid control

@NatoBoram hopefully that'll help you :)

@Lonli-Lokli
Copy link

Still no one from angular team interested in help for developers?

@devtronic
Copy link

Recursive iterating over the FormGroup works for me:

  public group: FormGroup;
  
  public getErrors(group?: FormGroup | FormArray): { [key: string]: ValidationErrors } | ValidationErrors[] | null {
    const errors = group instanceof FormArray ? [] : {};

    if (group == null) {
      group = this.group;
    }

    let idx = 0;
    Object.keys(group.controls).forEach((name) => {
      idx++;
      const control = group.get(name);
      if (control instanceof FormArray || control instanceof FormGroup) {
        const tmpErrors = this.getErrors(control as (FormArray | FormGroup));
        if (tmpErrors != null) {
          errors[name] = tmpErrors;
        }
      } else if (control instanceof FormControl) {
        if (control.errors == null) {
          return null;
        }
        if (group instanceof FormArray) {
          (errors as ValidationErrors[])[idx] = control.errors;
        } else {
          errors[name] = control.errors;
        }
      }
    });

    return (group instanceof FormGroup && Object.keys(errors).length === 0)
      || Array.isArray(errors) && errors.length === 0 ? null : errors;
  }

@etay2000
Copy link

Any chance someone from the Angular team might acknowledge this issue before it's four year anniversary?

@andrewatwood
Copy link

andrewatwood commented Dec 15, 2020

Any chance someone from the Angular team might acknowledge this issue before it's four year anniversary?

Lol it came and went...of all the requests people have for reactive forms, this seems like one of the more straightforward ones to solve in SOME capacity.

@etay2000
Copy link

I don't want to over-react, but recently I've started to vue things differently. Having started with Angular, I just assumed that all large open source projects just let heavily requested developer issues languish for years at a time. Come to find out, there are actually some large projects that actively work to resolve developer issues! They don't even have to make announcements about finally committing enough resources to get their issue tracker under control, because as crazy as this sounds, they never ignored the issues in their issue tracker in the first place!. Apparently pull requests are not supposed to take years for approval either! Who knew?
Don't worry though, whenever you start to worry about Angular, just refer to their 2020 roadmap for reassurance.

@mindscratch
Copy link

I stumbled onto this as well, and revamped the solution to find invalid control names found on stackoverflow, to return control errors recursively:

 public findErrorsRecursive(
    formToInvestigate: FormGroup | FormArray
  ): ValidationErrors[] {
    let errors: ValidationErrors[] = [];
    const recursiveFunc = (form: FormGroup | FormArray) => {
      Object.keys(form.controls).forEach((field) => {
        const control = form.get(field);
        if (control?.errors) {
          errors.push(control.errors);
        }
        if (control instanceof FormGroup) {
          recursiveFunc(control);
        } else if (control instanceof FormArray) {
          recursiveFunc(control);
        }
      });
    };
    recursiveFunc(formToInvestigate);
    return errors;
  }

@angular-robot angular-robot bot added the feature: under consideration Feature request for which voting has completed and the request is now under consideration label Jun 4, 2021
@EngAhmedShehatah
Copy link

I faced the same problem with form.invalid. It was false while the form group has a child form control with null value while required. I tried to use !form.valid and it worked fine. So I think it is a temporary solution till Angular Team solves the issue.
[+] adding to the problem, I tried to check the form.errors array and it was null while the form group has a child form control with null value while required as well.

@AndrewKushnir AndrewKushnir added this to Inbox in Feature Requests via automation Jul 13, 2021
@AndrewKushnir AndrewKushnir moved this from Inbox to Needs Discussion in Feature Requests Jul 13, 2021
@alxhub alxhub moved this from Needs Discussion to Backlog in Feature Requests Jul 15, 2021
@AndrewKushnir
Copy link
Contributor

Hi, just want to provide an update: we've discussed this feature request with the team and the conclusion is that we'd like to add the support to gather errors for the entire control tree, but doing so would increase bundle size for all apps (since it'd need to be added to the AbstractControl-based classes and the code there is non-tree-shakable). We have another open ticket that talks about tree-shaking (see #39640) and we'd need to resolve it first before we can add extra logic to gather errors.

This feature request is in the Backlog now, but we don't have any ETA at this moment.

@simeyla
Copy link

simeyla commented Nov 15, 2022

@AndrewKushnir surely there is a way to offer some sort of helper functions to do this (if bundle size is really what is holding this up). If you look at Stackoverflow you'll see incredibly high demand for such a feature. Why not offer some well tested helper functions - I don't want to spend hours reading over all the nuances of each of these options.

@azhdarshirinzada
Copy link

Any chance someone from the Angular team might acknowledge this issue before it's four year anniversary?

let me fix the sentence: *six years 🦁

@maxime1992
Copy link

@azhdarshirinzada your timeline

image

makes me think we've got more chance of seeing you post a comment notifying everyone here next year saying "*7 years" rather than getting a contribution from you to fix this issue. Feel free to prove me wrong though.

But as a reminder Angular is a free and open source project. You cannot have the same expectation as if you were paying something. Contribute yourself, pay a bounty for someone to raise a fix for you, or take a seat on the quiet bench of people kindly waiting for this to be solved.

We can all see the date of the issue and seeing comments like yours isn't helping in any way.

Anyone moderating this thread feel free to mark my comment as off topic (and @azhdarshirinzada 's comment too while we're at it...)

@cbossi
Copy link

cbossi commented Dec 4, 2022

If you use a ControlValueAccessor implementation for your nested form, you can use the following workaround to propagate the validation state to the parent form by registering a validator on the parent form's field:

export abstract class FormGroupComponent implements ControlValueAccessor, OnInit {

  public abstract readonly form: FormGroup;

  protected constructor(private readonly controlDir: NgControl | null) {
  }

  ngOnInit(): void {
    this.controlDir?.control?.setValidators(() => this.form.valid ? null : {});
  }

  [...]
}
  • form is the FormGroup containing the nested form's model
  • controlDir is the form field of the parent form referencing the nested form (ca be injected using @Optional() @Self())

Despite the validation state, also the pristine and dirty state can be propagated to the parent form. A complete example of such a base class can be found here: https://gist.github.com/cbossi/0979c7dcdc2e215e28772a11ccc602ab

@rsc092020
Copy link

rsc092020 commented Jun 21, 2023

Despite the validation state, also the pristine and dirty state can be propagated to the parent form. A complete example of such a base class can be found here: https://gist.github.com/cbossi/0979c7dcdc2e215e28772a11ccc602ab

I was looking at this and wondering if it's possible to make a change to setParent.
It seems like all of references to _parent make use of apis on AbstractControl anyways, so I was thinking that the type could be changed like this:

  setParent(parent: FormGroup|FormArray|null): void {
    this._parent = parent;
  }

TO

  setParent(parent: AbstractControl | null): void {
    this._parent = parent;
  }

Then, you would be able to call it like below to connect the touched, pristine, dirty, pending, and validity between the FormGroup created in the component, and the FormControl attached to the component via directive.

this.form.setParent(this.control)

This would be instead of hooking into statusChanges to update the pristine, dirty, etc on the parent FormControl, like in @cbossi example code. I do agree with that example though as far as what's currently in the public api. You would still need the rest of FormGroupComponent, but at least it would make it a little easier.

@JeanMeche
Copy link
Member

For those following this issue, what would you think of providing this feature by providing errors via the unified control state event observable ? (related to #54579 & #48947)

@michael-small
Copy link

For those following this issue, what would you think of providing this feature by providing errors via the unified control state event observable ? (related to #54579 & #48947)

I think this would be a great application of the unified events. I have found myself wanting something like an errorChanges quite often. Even yesterday at work I was like... something like error events would solve so many of the issues I am working through on a new feature and previous ones. Any form of error reactivity would be a huge win.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area: forms feature: under consideration Feature request for which voting has completed and the request is now under consideration feature Issue that requests a new feature freq3: high state: Needs Design
Projects
No open projects
Development

No branches or pull requests