15

I am building a deep nested form with Angular2 and FormGroup, currently I have a form such as in a parent controller:

this.orderForm = this.fb.group({

customerSelectForm: this.fb.group({ // create nested formgroup to pass to child
        selectTypeahead: ['', 
                            Validators.required],
        })
})

Then in a child component I have:

<div class="form-group" [formGroup]="customerSelectForm" *ngIf="customerSelectForm">
        <label for="oh-custaccount">Customer Account #</label>

    <input class="form-control" type="text" 
    formControlName="selectTypeahead"
    (focusout)=someFunction() />

    <p *ngIf="customerSelectForm.controls.selectTypeahead.errors?.required">
    Number required!</p>
</div>

Now this child template works fine, and renders an error on screen if there is no input inside the text box. I then back in the parent controller have a submit button:

<button type="submit" class=" btn btn-success" [disabled]="orderForm?.invalid">Submit</button>

Again, this works as expected, and only is enabled after an input is registered in the selectTypeahead input.

Now due to the large nature of this form, I want to have a display next to the submit button, that lists all form elements, which are currently failing. I did try rendering:

{{orderForm.errors}}

But this stayed as "null" even when my form was invalid, how would I list all inputs from orderFrom that have currently not passed/matched their corresponding validation rules?

7
  • take a look at this link it removes all the code from the html and places it in the ts files github.com/rahulrsingh09/AngularConcepts/blob/master/src/app/… Commented May 23, 2017 at 13:53
  • Yea, so basically I need to subscribe to the form, when its changed, force all data through a validation, return errors to each component, then I can also return all errors as one to the template as a summary? Commented May 23, 2017 at 14:05
  • 1
    I have decided to create a service, each component will connect to an observable there, if an input has a validation failure, it will report to this service, then I can subscribe to its result and view all current errors, will post a working plunker soon, Commented May 23, 2017 at 16:00
  • 1
    If {{orderForm.errors}} says null when it's invalid you have some other issue. Commented May 25, 2017 at 19:33
  • Thanks, I now know the root form errors property is now related to the actual form layout itself, other than validation errors. Commented May 26, 2017 at 7:19

1 Answer 1

29

I think you have to recursively visit the descendants controls of your form to obtain all errors.

getAllErrors(form: FormGroup | FormArray): { [key: string]: any; } | null {
    let hasError = false;
    const result = Object.keys(form.controls).reduce((acc, key) => {
        const control = form.get(key);
        const errors = (control instanceof FormGroup || control instanceof FormArray)
            ? this.getAllErrors(control)
            : control.errors;
        if (errors) {
            acc[key] = errors;
            hasError = true;
        }
        return acc;
    }, {} as { [key: string]: any; });
    return hasError ? result : null;
}

Then in your template

<!--
  NOTE: This is just for displaying the result of the method
  You should replace the `<pre><code>` with whatever your snippet is like
-->
<pre><code>{{ getAllErrors(orderForm) | json }}</code></pre>
Sign up to request clarification or add additional context in comments.

1 Comment

This solution does not return the error on the form itself but only on all FormControls and their descendants.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.