Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angular ControlValueAccessor and markAsTouched

I'm using angular 9 with Angular Material and I have a custom control by implementing the ControlValueAccessor interface. Everything is working fine.

In all my submit buttons when the form is not valid, I call formGroup.markAllAsTouched because all the angular material fields become in red. In this way the user can better understand which controls are not valid.

I need to implement the same behavior with my custom control. How to do that?

I've created a stackblitz project in order to better understand the situation here

like image 870
Gavi Avatar asked May 02 '20 21:05

Gavi


People also ask

What is Controlvalueaccessor in Angular?

Control Value Accessor is an interface that provides us the power to leverage the Angular forms API and create a communication between Angular Form API and the DOM element. It provides us many facilities in angular like we can create custom controls or custom component with the help of control value accessor interface.

What is form control and form group in Angular?

FormControl and FormGroup in AngularFormGroup is used with FormControl to track the value and validate the state of form control. In practice, FormGroup aggregates the values of each child FormControl into a single object, using each control name as the key.

What is markAsPristine Angular?

markAsPristine() Marks the control as pristine. Angular documentation for form control's validatior api— https://angular.io/api/forms/AbstractControl.


1 Answers

There is no built-in functionality for propagating touched status to inner FormControl of custom control.

Your simple option would be checking status in ngDoCheck and once custom control becomes touched update status for inner FormControl:

ngDoCheck() {
  if (this.formControl.touched) {
    return;
  }
  if (this.controlDir.control.touched) {
    this.formControl.markAsTouched();
  }
}

Forked Stackblitz

Personally, I don't like such kind of implementations with ControlValueAccessor. I would rather use the same FormControl. This can be done by adding viewProviders with ControlValueAccessor provider to your custom control:

custom-control.component.ts

@Component({
  selector: 'my-custom-control',
  template: `
    <mat-form-field id="userType">
      <mat-label>My Custom Component</mat-label>
      <mat-select [formControlName]="controlName" (blur)="onTouched()">
        <mat-option *ngFor="let current of userTypes" [value]="current.id">{{current.name}}</mat-option>
      </mat-select>
    </mat-form-field>

  `,
   viewProviders: [{
    provide: ControlContainer,
    useFactory: (container: ControlContainer) => container,
    deps: [[new SkipSelf(), ControlContainer]],
 }]
})
export class MyCustomControl {
  @Input() controlName: string;

  userTypes: LookupModel[] = [
      new LookupModel(1, 'first'),
      new LookupModel(2, 'second')
  ];
}

parent html

<form [formGroup]="form">
  <my-custom-control controlName="userTypeCustomControl"></my-custom-control>

Stackblitz Example

like image 52
yurzui Avatar answered Sep 19 '22 09:09

yurzui