我想将角材料的matInput封装在组件中,以便在应用程序的其他位置重用它,因为我需要管理其内部状态,以将输入类型从文本更改为密码,反之亦然。
我设法通过实现ControlValueAccessor来做到这一点,但是没有显示验证错误的样式。
密码字段部分:
export class PasswordFieldComponent
implements OnInit, ControlValueAccessor {
@ViewChild(DefaultValueAccessor) private valueAccessor: DefaultValueAccessor;
@Input() customClass: string;
@Input() customPlaceholder: string;
@Input() required = true;
hide = true;
constructor() { }
ngOnInit() {
}
private propagateChange = (_: any) => { };
private onChange(event) {
this.propagateChange(event.target.value);
}
private onTouch() { }
registerOnChange(fn: any): void {
this.valueAccessor.registerOnChange(fn);
}
registerOnTouched(fn: any): void {
this.valueAccessor.registerOnTouched(fn);
}
setDisabledState(isDisabled: boolean): void {
this.valueAccessor.setDisabledState(isDisabled);
}
writeValue(value: any): void {
this.valueAccessor.writeValue(value);
}
}
密码字段模板:
<mat-form-field class="full-width {{ customClass }}">
<input
matInput
ngDefaultControl
placeholder="{{ customPlaceholder }}"
[required]="required"
[type]="hide ? 'password' : 'text'"
(input)="onChange($event)">
<button mat-icon-button matSuffix (click)="hide = !hide" [attr.aria-label]="'Hide password'" [attr.aria-pressed]="hide">
<mat-icon>{{hide ? 'visibility_off' : 'visibility'}}</mat-icon>
</button>
</mat-form-field>
The code from my comments is make the "most simple custom form control that has a material input inside". The idea is create custom ErrorStateMatcher that ask about the control itself. So, out inner material input show errors not when it was invalid else when our custom control was invalid
This ErrorStateMatcher need the know about our control, so we are going to create a constructor to inject this control (I inject in constructor another object "errors" to alow make "invalid" the material input)
class CustomFieldErrorMatcher implements ErrorStateMatcher {
constructor(private customControl: FormControl,private errors:any) { }
isErrorState(control: FormControl | null, form: FormGroupDirective | NgForm | null): boolean {
return this.customControl && this.customControl.touched &&(this.customControl.invalid || this.errors);
}
}
The .html is like
<mat-form-field>
<input #input="ngModel" [ngModel]="value" (ngModelChange)="value=$event;onChange($event)"
matInput
[errorStateMatcher]="errorMatcher()"
[placeholder]="placeholder"
[type]="hide ? 'password' : 'text'"
(blur)="onTouched()"
>
<button mat-icon-button matSuffix (click)="hide = !hide" [attr.aria-label]="'Hide password'" [attr.aria-pressed]="hide">
<mat-icon>{{hide ? 'visibility_off' : 'visibility'}}</mat-icon>
</button>
<mat-error *ngIf="control?.errors?.required">
Please enter a {{placeholder}}
</mat-error>
<mat-error *ngIf="errors?.errorMatch">
Must match
</mat-error>
</mat-form-field>
The most important part is this
[errorStateMatcher]="errorMatcher()"
看到使用[ngModel]和(ngModel),(模糊)将自定义formControl标记为“ touched”。我添加了一个mat-error * ngIf =“ errors?.errorMatch。这是一个@Input()
获取Form的error值的代码。这是因为如果两个字段“ password”和“ repeatpassword”使我们拥有一个自定义错误的FormGroup, “ 不匹配。
我们的自定义表单控件就像
export class CustomSelectComponent implements AfterViewInit, ControlValueAccessor {
control: FormControl
onChange: any = () => { };
onTouched: any = () => { };
value: any;
@Input() disabled: boolean;
@Input() placeholder = '';
@Input() errors:any=null;
errorMatcher() {
return new CustomFieldErrorMatcher(this.control,this.errors)
}
constructor(public injector: Injector) {
}
ngAfterViewInit(): void {
const ngControl: NgControl = this.injector.get(NgControl, null);
if (ngControl) {
setTimeout(() => {
this.control = ngControl.control as FormControl;
})
}
}
查看如何在ngAfterViewInit中获取ngControl,如何errorMatcher()返回新的CustomFieldErrorMatcher以及如何传递“ control”和“ errors”的值。
好吧,我们的app.component就像
ngOnInit() {
this.myForm = new FormGroup(
{
password: new FormControl("", Validators.required),
repeatpassword: new FormControl("", Validators.required)
},
this.matchControls("password", "repeatpassword")
);
}
matchControls(field1, field2) {
return (group: FormGroup) => {
const control1 = group.get(field1);
const control2 = group.get(field2);
return control1 && control2 &&
control1.value && control2.value &&
control1.value != control2.value
? { errorMatch: "must match" }: null;
};
}
app.component的.html是
<form [formGroup]="myForm" autocomplete="off">
<app-custom-input placeholder="Password" formControlName="password" >
</app-custom-input>
<app-custom-input placeholder="Repeat password" formControlName="repeatpassword" [errors]="myForm.errors?.errorMatch?myForm.errors:null" >
</app-custom-input>
</form>
在自定义组件上添加了此侦听器。您也可以将其“模糊”事件。
https://stackoverflow.com/a/59086644/12425844
@HostListener('focusout', ['$event.target'])
onFocusout() {
this.onTouched();
}
And also calling onTouched when setting any value.
writeValue(value: any) {
this.onTouched();
this.Value = value ? value : '';
}
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句