angular / components

Component infrastructure and Material Design components for Angular
https://material.angular.io
MIT License
24.32k stars 6.73k forks source link

mat-error does not display on submit when fields are added in a FormArray #9007

Open losbeekos opened 6 years ago

losbeekos commented 6 years ago

Bug, feature request, or proposal:

The mat-error directive doesn't display on submit when fields are added in a FormArray. The error is shown when you touch the field. Also when I change the mat-error to a regular div, the div is just being shown.

What is the expected behavior?

Show mat-error on submit when field is untouched.

What is the current behavior?

Does not show mat-error on submit when field is untouched.

What are the steps to reproduce?

Repro: https://angular-material2-issue-ttt1jk.stackblitz.io/

I have HTML like this:

Or:

What is the use-case or motivation for changing an existing behavior?

Validation needs to be shown on submit so the user knows the field has errors.

Which versions of Angular, Material, OS, TypeScript, browsers are affected?

Is there anything else we should know?

willshowell commented 6 years ago

Think you could provide a stackblitz reproduction?

losbeekos commented 6 years ago

I've made a quick stackblitz: https://angular-material2-issue-ttt1jk.stackblitz.io The 'name' field is just a regular field, the 'test' field is added in a FormArray.

Making this stackblitz I've came to the conclusion the problem doesn't lie when a FormControl is added to a FormArray. The problem arises when the FormControl is added with a component, as demonstrated in the stackblitz.

willshowell commented 6 years ago

@losbeekos I think the only issue is with how you're adding new controls to your FormArray.

Fix

Instead of this,

control.push(this.formBuilder.group(groupObject['test'] = ['', Validators.required]));

do this,

control.push(this.formBuilder.group({
  test: ['', Validators.required]
}));

Explanation

The expression groupObject['test'] = ['', Validators.required] doesn't return an updated groupObject, it just returns ['', Validations.required].

losbeekos commented 6 years ago

Can you look again? I think you had an old revision of the stackblitz.

The problem lies when I use a component. With component: https://angular-material2-issue-ttt1jk.stackblitz.io/ Without component: https://angular-material2-issue-ywwtjf.stackblitz.io

mmalerba commented 6 years ago

Posting links to above stackblitz's w/ code for convenience: https://stackblitz.com/edit/angular-material2-issue-ttt1jk https://stackblitz.com/edit/angular-material2-issue-ywwtjf

losbeekos commented 6 years ago

Any update on this?

mmalerba commented 6 years ago

This is probably because the ErorrStateMatcher only receives the NgForm and FormGroupDirective, it probably needs to consider the FormArrayDirective too.

https://github.com/angular/material2/blob/0834a31d03ae6707633e01d43200703840b70c5a/src/lib/input/input.ts#L226

natrayanp commented 6 years ago

Facing the same issue.
1) Field ( XXX :new FormControl('',Validators.required)) is not marked as ERROR when the page is loaded and it is empty. When field is touched it is shown as ERROR. 2) None of matError is shown untill the field in the FormArray is touched.

gowthamrodda commented 6 years ago

facing same issue. Any update on this?

pfeigl commented 6 years ago

@mmalerba I have the feeling the problem is a little different. The check that's actually failing is this: https://github.com/angular/material2/blob/f5377ddd7352890644f5333a9a9a498580c2b92c/src/lib/core/error/error-options.ts#L24

The problem is, that the submitted property for FormGroupDirective is not changed to true (while the submitted state for the actual form is) and thus it is never reported as "in error state" even so the control.invalid is actually true.

I think this is actually a problem we need to log in @angular/forms

pfeigl commented 6 years ago

I actually found the related tickets to this: https://github.com/angular/angular/issues/21263: Describes the actual problem and states that it won't be changed - for good reasons https://github.com/angular/angular/issues/21823: Describes a potential solution (with a link to exactly the problem we are having here) but has no progress as of yet

For a fix, you guys could try to get a reference to the ViewChild of your component, in their get a reference to the FormGroupDirective and in the submit handler of the parent set the childs submitted property to true. This would be done something like this (this.formGroupDirective as{submitted: boolean}).submitted = true; because submitted is marked readonly.

Didn't test that and I'm not sure whether input validation might kick in too early for this to work. Probably you just have to wait for https://github.com/angular/angular/issues/21823 to be fixed and than for @angular/material2 to adjust to those fixes.

@mmalerba: If what I'm saying is correct, we probably have to remove the help wanted label and create a new issue to adjust on our side to a potential change in the angular issue or atleast have a TODO in the code of error-options.ts

mmalerba commented 6 years ago

@pfeigl Ok I've removed the help wanted label since it seems to be a deeper issue with forms. I'll leave this issue open for now in case there's any work we have to do after the changes in angular/angular.

chmielewskitomasz commented 6 years ago

Same here. mat-error not displaying errors unless touched

michael-letcher commented 6 years ago

@chmielewskitomasz Dose the class mat-form-field-invalid appear?

We're having issues with our Dynamic (Reactive) forms, in that the fields do no go to an error state on submit only by being touched to do they change.

scne commented 3 years ago

up

mohamedassem96 commented 3 years ago

still no solution?

Totati commented 3 years ago

Use ControlContainer in viewProviders. Example

rgurgul commented 2 years ago

workaround // onsubmit this.form.markAllAsTouched();

Belgacemzabbes commented 1 year ago

Create a method like onChange() or onKeyup()... It depends on the event handler

// Ts file onChange(){ this.form.controls['targetField'].markAsTouched(); }

//Html File <input (change)="onChange()">

This has worked for me