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
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.
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.
markAsPristine() Marks the control as pristine. Angular documentation for form control's validatior api— https://angular.io/api/forms/AbstractControl.
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
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