Я пытаюсь создать оболочку для компонента флажка из материала angular, но получаю сообщение об ошибке «поле формы-мат должно содержать MatFormFieldControl», хотя класс реализует интерфейс MatFormFieldControl. Идея состоит в том, чтобы показать ошибки для компонента custom-checkbox в самом компоненте, а также иметь возможность передавать настраиваемые сообщения об ошибках от родителя. Пожалуйста, помогите мне в этом. Спасибо!
custom-checkbox.component.ts
import { Component, OnInit, Input, Self, Optional, Output, EventEmitter, HostBinding, Injector, DoCheck, ElementRef, ViewChild } from '@angular/core';
import { ControlValueAccessor, FormControl, NgControl, ValidatorFn, Validators } from '@angular/forms';
import { MatFormFieldControl } from '@angular/material/form-field';
import { Subject } from 'rxjs';
import { coerceBooleanProperty } from '@angular/cdk/coercion';
@Component({
host: {
'[id]': 'id',
'[attr.aria-describedby]': 'describedby'
},
selector: 'custom-checkbox',
templateUrl: './custom-checkbox.component.html',
styleUrls: ['./custom-checkbox.component.scss'],
providers: [
{ provide: MatFormFieldControl, useExisting: CustomCheckboxComponent }
]
})
export class CustomCheckboxComponent implements OnInit, DoCheck, ControlValueAccessor, MatFormFieldControl<boolean> {
public _required: boolean = false;
private _disabled: boolean = false;
private _checked: boolean = false;
customFormControl: FormControl;
validators: ValidatorFn | ValidatorFn[];
name: string = "checkbox-name";
static nextId = 0;
// from implementing MatFormFieldControl
stateChanges: Subject<void> = new Subject<void>();
placeholder: string;
ngControl: NgControl;
focused: boolean = false;
shouldLabelFloat: boolean;
errorState: boolean = false;
controlType?: string = "customCheckbox";
autofilled?: boolean;
@Input() checkboxData: any;
@Input() get required() { return this._required; }
set required(req) {
this._required = coerceBooleanProperty(req);
this.stateChanges.next();
}
@Input() get value(): boolean {
return this._checked;
}
set value(value) {
this._checked = coerceBooleanProperty(value);
this.customFormControl.setValue(this._checked);
this.propagateChange(value);
this.stateChanges.next();
}
get empty() {
if (this.customFormControl.pristine || this.customFormControl.untouched) return true;
else return false;
}
@Input() get disabled(): boolean { return this._disabled; }
set disabled(value) {
this._disabled = coerceBooleanProperty(value);
this._disabled ? this.customFormControl.disable() : this.customFormControl.enable();
this.stateChanges.next();
}
@Output() checkboxEvent: EventEmitter<any>;
@HostBinding('attr.aria-describedby') describedBy = '';
@HostBinding() id = `custom-checkbox-component-${CustomCheckboxComponent.nextId++}`;
constructor(@Optional() @Self() public controlDir: NgControl, public injector: Injector) {
this.customFormControl = new FormControl();
this.checkboxEvent = new EventEmitter();
if (this.controlDir != null) {
this.controlDir.valueAccessor = this;
}
}
ngOnInit(): void {
this.ngControl = this.injector.get(NgControl);
if (this.ngControl != null) this.ngControl.valueAccessor = this;
this.validators = this.required ? Validators.required : this.validators;
this.customFormControl.setValidators(this.validators);
this.customFormControl.updateValueAndValidity();
}
ngDoCheck() {
if (this.ngControl) {
this.errorState = this.ngControl.invalid && (this.ngControl.touched || this.ngControl.dirty);
this.stateChanges.next();
}
}
setDescribedByIds(ids: string[]): void {
this.describedBy = ids.join(' ');
}
onContainerClick(event: MouseEvent): void {
// throw new Error("Method not implemented.");
}
propagateChange = (_: any) => { };
onTouched = () => { };
writeValue(value: any): void {
if (value != undefined) this.customFormControl.setValue(value);
}
registerOnChange(fn: (_: any) => {}): void {
this.propagateChange = fn;
}
registerOnTouched(fn: () => {}): void {
this.onTouched = fn;
}
setDisabledState(isDisabled: boolean): void {
// this.disabled = isDisabled;
}
selectionChanged(event: any) {
console.info("Checkbox %s : ", event.checked, event.source.value);
this.stateChanges.next()
this.checkboxEvent.emit(event.checked);
}
ngOnDestroy() {
this.stateChanges.complete();
}
}
custom-checkbox.component. html
<mat-form-field>
<mat-checkbox #checkbox [formControl]="customFormControl" [name]="name" [required]="this.required" [value]="this.checkboxData"
[checked]="value" (change)="selectionChanged($event);propagateChange($event.checked)">
{{checkboxData?.value}}</mat-checkbox>
<mat-error *ngIf="customFormControl.invalid && (customFormControl.dirty || customFormControl.touched)">
Error Message
</mat-error>
</mat-form-field>