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?
To prevent the validator from displaying errors before the user has a chance to edit the form, you should check for either the dirty or touched states in a control. When the user changes the value in the watched field, the control is marked as "dirty"
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>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With