0
votes

I am using Angular 7, Angular Material controls with Reactive Forms.

I created custom text (matInput type="text"), number (matInput type="number"), select (matSelect) controls with Angular Material with mat-form-field

Here is the stackblitz for my example.

I am trying to attach the custom form controls to reactive form and trying to fire any validations on the form group automatically.

I am using ControlValueAccessor to achieve this, however my Select is not being identified as form control and no value is being recorded in the form control on the form.

Any help in this regard is highly appreciated.

1
just use (selectionChange)="onChange($event.value)"Eliseo

1 Answers

2
votes

UPDATE Jenson-button-event find a better option, see the SO answer

Looking into your code, I see that you use Angular Material to create your custom FormControl. Well, The problem when use Angular material is how make that the "errors" appears.

When we use <mat-error> the error appears if the control is invalid. Take account that is invalid our custom form conrol, NOT the input-material. How avoid this inconvenience?

The solution is using a CustomFieldErrorMatcher. if we can create a CustomFiledErrorMatcher that take account the errors of our customFormControl, we can do some like

class CustomFieldErrorMatcher implements ErrorStateMatcher {
  constructor(private customControl: FormControl) { }
  isErrorState(control: FormControl | null, form: FormGroupDirective | NgForm | null): boolean {
    return control.dirty && this.customControl.invalid;
  }
}

Well, it's only in ngAfterView write some like

  ngAfterViewInit(): void {
    const ngControl: NgControl = this.injector.get(NgControl, null);
    if (ngControl) {
      setTimeout(() => {
        this.control = ngControl.control as FormControl;
      })
    }
  }

Has a function

errorMatcher() {
    return new CustomFieldErrorMatcher(this.control)
  }

And create our custom-formControl.html like

<mat-form-field>
    <mat-select [ngModel]="value" (ngModelChange)="value=$event;onChange($event)" 
          [placeholder]="placeholder" [disabled]="disabled"
          [errorStateMatcher]="errorMatcher()">
        <mat-option *ngFor="let option of optionList" [value]="option.value">
            {{ option.label }}
        </mat-option>
    </mat-select>
  <mat-error *ngIf="control?.hasError('required')">Required</mat-error>
  <mat-error *ngIf="control?.hasError('error')">{{control?.errors.error}}</mat-error>
</mat-form-field>

You can see in the stackblitz two forms, one that use a customFormControl, and another one in clasic mode