使用验证器创建自定义 FormControl
Create custom FormControl with Validators
我创建了一个使用 Material 设计的组件 (AComponent),我想将它用作我的 Reactive Form(在 AppComponent 中)中的 formControl。
我已经在这个组件 (AComponent) 中实现了 ControlValueAccessor
。
export class AComponent implements ControlValueAccessor {
fm = new FormControl();
constructor(private ngControl: NgControl) {
ngControl.valueAccessor = this;
this.fm.valueChanges.subscribe(v => {
this.onChange(v);
})
}
onChange = (_: any) => {}
onTouched = () => {}
writeValue(obj: any) {
this.fm.setValue(obj);
}
registerOnChange(fn: any) {
this.onChange = fn;
}
registerOnTouched(fn: any) {
this.onTouched = fn;
}
}
我可以为这个组件(在 AppComponent 中)设置 Validators.required
ngOnInit() {
this.formGroup = this.fb.group({
control: ['', Validators.required],
controlOne: ['', Validators.required]
})
this.formGroup.statusChanges
.subscribe(console.log);
}
它会影响整个表单。 (可以在控制台看到:ACompnent无效时无效)。
但问题是我无法强制 AComponent 看起来无效(红色输入),以防它无效。
看起来内部 formControl(在 AComponent 中)没有从 AppComponent 获得 Validators.required
。
问题是:如何以优雅的方式将验证器设置为 AComponent?
您需要提供NG_VALIDATORS
https://medium.com/@tarik.nzl/angular-2-custom-form-control-with-validation-json-input-2b4cf9bc2d73
providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => CustomInputComponent),
multi: true
},
{
provide: NG_VALIDATORS,
useExisting: forwardRef(() => CustomInputComponent),
multi: true
}
]
您也可以选择使用 @Hostbinding
设置 ng-error 类
注意 当我们创建自定义表单控件时,Angular 添加 ng-invalid ng-touched 到我们的组件。所以,通常我们使用 .css
来改变控件的外观
.ng-invalid.ng-touched
{
color:red;
}
问题是我们想要在自定义表单控件中更改 mat-input 的外观。所以我们需要知道什么时候我们的控制无效。
在 this stackblitz 中,您有自己的自定义表单控件。
关键是知道您的自定义表单控件何时无效。为此,whe 可以注入 ngControl。必须使用 inject 来避免循环依赖。所以,我们的构造函数就像
constructor(public injector: Injector) { }
ngOnInit() {
this.ngControl = this.injector.get(NgControl);
this.fm.valueChanges.subscribe(v => {
this.onChange(v);
})
}
好吧,我们知道自定义控件何时有效、触及、原始...
我们将定义一个 .css like
.customError,.custom
{
display:inline-block;
}
.customError .mat-form-field-empty.mat-form-field-label {
color: red!important;
}
.customError .mat-form-field-underline {
background-color: red!important;
}
并在我们的组件中使用 ViewEncapsulation.None。 ViewEncapsulation.None 使 .css 在所有应用程序中。这是因为我们在.mat-form-field-empty.mat-form-field-label和mat-form-field-underline之前添加了class“.customError”。否则我们所有的 mat-components 看起来都有错误。
@Component({
selector: 'app-a',
templateUrl: './a.component.html',
styleUrls: [ './a.component.css' ],
encapsulation:ViewEncapsulation.None,
providers: [{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => AComponent),
multi: true
}]
})
在此之后,我们使用 [ngClass] 添加 classes
<div class="custom"
[ngClass]="{'customError':ngControl.invalid && ngControl.touched}" >
<mat-form-field
[color]="ngControl.invalid && ngControl.touched?'warn':null" >
<input matInput placeholder="Some value" [formControl]="fm" (blur)="onTouched()">
</mat-form-field>
</div>
看到我们在mat-form-field中使用属性[颜色]使波纹下划线也变成红色以及我们如何使用(模糊)标记为已触摸控件
我创建了一个使用 Material 设计的组件 (AComponent),我想将它用作我的 Reactive Form(在 AppComponent 中)中的 formControl。
我已经在这个组件 (AComponent) 中实现了 ControlValueAccessor
。
export class AComponent implements ControlValueAccessor {
fm = new FormControl();
constructor(private ngControl: NgControl) {
ngControl.valueAccessor = this;
this.fm.valueChanges.subscribe(v => {
this.onChange(v);
})
}
onChange = (_: any) => {}
onTouched = () => {}
writeValue(obj: any) {
this.fm.setValue(obj);
}
registerOnChange(fn: any) {
this.onChange = fn;
}
registerOnTouched(fn: any) {
this.onTouched = fn;
}
}
我可以为这个组件(在 AppComponent 中)设置 Validators.required
ngOnInit() {
this.formGroup = this.fb.group({
control: ['', Validators.required],
controlOne: ['', Validators.required]
})
this.formGroup.statusChanges
.subscribe(console.log);
}
它会影响整个表单。 (可以在控制台看到:ACompnent无效时无效)。
但问题是我无法强制 AComponent 看起来无效(红色输入),以防它无效。
看起来内部 formControl(在 AComponent 中)没有从 AppComponent 获得 Validators.required
。
问题是:如何以优雅的方式将验证器设置为 AComponent?
您需要提供NG_VALIDATORS
https://medium.com/@tarik.nzl/angular-2-custom-form-control-with-validation-json-input-2b4cf9bc2d73
providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => CustomInputComponent),
multi: true
},
{
provide: NG_VALIDATORS,
useExisting: forwardRef(() => CustomInputComponent),
multi: true
}
]
您也可以选择使用 @Hostbinding
设置 ng-error 类注意 当我们创建自定义表单控件时,Angular 添加 ng-invalid ng-touched 到我们的组件。所以,通常我们使用 .css
来改变控件的外观.ng-invalid.ng-touched
{
color:red;
}
问题是我们想要在自定义表单控件中更改 mat-input 的外观。所以我们需要知道什么时候我们的控制无效。
在 this stackblitz 中,您有自己的自定义表单控件。
关键是知道您的自定义表单控件何时无效。为此,whe 可以注入 ngControl。必须使用 inject 来避免循环依赖。所以,我们的构造函数就像
constructor(public injector: Injector) { }
ngOnInit() {
this.ngControl = this.injector.get(NgControl);
this.fm.valueChanges.subscribe(v => {
this.onChange(v);
})
}
好吧,我们知道自定义控件何时有效、触及、原始...
我们将定义一个 .css like
.customError,.custom
{
display:inline-block;
}
.customError .mat-form-field-empty.mat-form-field-label {
color: red!important;
}
.customError .mat-form-field-underline {
background-color: red!important;
}
并在我们的组件中使用 ViewEncapsulation.None。 ViewEncapsulation.None 使 .css 在所有应用程序中。这是因为我们在.mat-form-field-empty.mat-form-field-label和mat-form-field-underline之前添加了class“.customError”。否则我们所有的 mat-components 看起来都有错误。
@Component({
selector: 'app-a',
templateUrl: './a.component.html',
styleUrls: [ './a.component.css' ],
encapsulation:ViewEncapsulation.None,
providers: [{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => AComponent),
multi: true
}]
})
在此之后,我们使用 [ngClass] 添加 classes
<div class="custom"
[ngClass]="{'customError':ngControl.invalid && ngControl.touched}" >
<mat-form-field
[color]="ngControl.invalid && ngControl.touched?'warn':null" >
<input matInput placeholder="Some value" [formControl]="fm" (blur)="onTouched()">
</mat-form-field>
</div>
看到我们在mat-form-field中使用属性[颜色]使波纹下划线也变成红色以及我们如何使用(模糊)标记为已触摸控件