Angular 中没有引用的自定义控件中的 setValidators
setValidators in custom control without from reference in Angular
我已经创建了一个自定义输入控件。我不想创建任何自定义验证。我想使用默认要求、minLength、maxLength etc.I 知道我可以这样做
this.form.controls["firstName"].setValidators([Validators.minLength(1), Validators.maxLength(30)]);
但我无法从父组件发送表单引用。我如何在文本框组件中使用 setValidator。
// input-box.component.ts
import { Component, Input, forwardRef } from '@angular/core';
import { NG_VALUE_ACCESSOR, ControlValueAccessor } from '@angular/forms';
@Component({
selector: 'app-input-box',
template:`<label >{{inputdata.label}}</label><br>
<input type="text" required #textBox [value]="textValue" (keyup)="onChange($event.target.value)" />`,
styleUrls: ['./input-box.component.less'],
providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => InputBoxComponent),
multi: true
},
/*{
provide: NG_VALIDATORS,
useExisting: forwardRef(() => InputBoxComponent),
multi: true,
}*/]
})
export class InputBoxComponent implements ControlValueAccessor {
@Input() inputdata: any;
private textValue: any = '';
onChange(value) {
this.textValue = value;
this.propagrateChange(value);
}
private propagrateChange = (_: any) => { };
writeValue(value: any) {
if (this.inputdata.value) {
this.textValue = this.inputdata.value;
this.propagrateChange(this.inputdata.value);
}
}
registerOnChange(fn: (value: any) => any) {
this.propagrateChange = fn;
}
registerOnTouched() { }
}
在不同的组件中使用
<app-input-box name="textBoxParent_{{index}}" [inputdata]="goaldata" ngModel ></app-input-box>
如果您想访问 class 中的 FormControl
,而该 class 想要实现 ControlValueAccessor
,您必须更改通常的实现方式。您不能在提供程序数组中将 class 注册为 ControlValueAccessor
并在构造函数中注入 FormControl
。因为 FormControl 将尝试注入您的 class,而您将尝试注入控件,这将创建循环依赖。
所以你需要做的修改如下:
- 从
providers
数组中删除 NG_VALUE_ACCESSOR
和 NG_VALIDATORS
。
在构造函数中注入NgControl
并设置控件的ControlValueAccessor和Validators。
constructor(@Self() ngControl: NgControl) {
ngControl.valueAccessor = this;
ngControl.setValidators([Validators.minLength(1), Validators.maxLength(30)]
ngControl.updateValueAndValidity()
}
如果您想保留自定义表单组件的消费者指定的验证器,您需要将构造函数修改为:
constructor(@Self() ngControl: NgControl) {
const control = ngControl.control;
let myValidators = [Validators.required, Validators.minLength(5)];
let validators = control.validator
? [control.validator, ...myValidators]
: myValidators;
control.setValidators(validators)
control.updateValueAndValidity();
}
查看 Kara Erickson(angular 核心)在 AngularConnect 2017 上解释的整个过程。Link
您也可以保持代码不变,只需从 Injector
中获取 NgControl
,如下所示:
constructor(private injector: Injector) {
}
public ngAfterViewInit(): void {
const ngControl = this.injector.get(NgControl);
const control = ngControl.control;
// Do whatever you want with validators now:
control.setValidators(validators)
control.updateValueAndValidity();
}
您将需要使用生命周期挂钩 ngAfterViewInit
否则控件将不可用。
这样你就跳过了循环依赖的问题,你可以将 NG_VALUE_ACCESSOR
和 NG_VALIDATORS
留在 providers
数组中。
见。
建议使用注射器
我已经创建了一个自定义输入控件。我不想创建任何自定义验证。我想使用默认要求、minLength、maxLength etc.I 知道我可以这样做
this.form.controls["firstName"].setValidators([Validators.minLength(1), Validators.maxLength(30)]);
但我无法从父组件发送表单引用。我如何在文本框组件中使用 setValidator。
// input-box.component.ts
import { Component, Input, forwardRef } from '@angular/core';
import { NG_VALUE_ACCESSOR, ControlValueAccessor } from '@angular/forms';
@Component({
selector: 'app-input-box',
template:`<label >{{inputdata.label}}</label><br>
<input type="text" required #textBox [value]="textValue" (keyup)="onChange($event.target.value)" />`,
styleUrls: ['./input-box.component.less'],
providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => InputBoxComponent),
multi: true
},
/*{
provide: NG_VALIDATORS,
useExisting: forwardRef(() => InputBoxComponent),
multi: true,
}*/]
})
export class InputBoxComponent implements ControlValueAccessor {
@Input() inputdata: any;
private textValue: any = '';
onChange(value) {
this.textValue = value;
this.propagrateChange(value);
}
private propagrateChange = (_: any) => { };
writeValue(value: any) {
if (this.inputdata.value) {
this.textValue = this.inputdata.value;
this.propagrateChange(this.inputdata.value);
}
}
registerOnChange(fn: (value: any) => any) {
this.propagrateChange = fn;
}
registerOnTouched() { }
}
在不同的组件中使用
<app-input-box name="textBoxParent_{{index}}" [inputdata]="goaldata" ngModel ></app-input-box>
如果您想访问 class 中的 FormControl
,而该 class 想要实现 ControlValueAccessor
,您必须更改通常的实现方式。您不能在提供程序数组中将 class 注册为 ControlValueAccessor
并在构造函数中注入 FormControl
。因为 FormControl 将尝试注入您的 class,而您将尝试注入控件,这将创建循环依赖。
所以你需要做的修改如下:
- 从
providers
数组中删除NG_VALUE_ACCESSOR
和NG_VALIDATORS
。 在构造函数中注入
NgControl
并设置控件的ControlValueAccessor和Validators。constructor(@Self() ngControl: NgControl) { ngControl.valueAccessor = this; ngControl.setValidators([Validators.minLength(1), Validators.maxLength(30)] ngControl.updateValueAndValidity() }
如果您想保留自定义表单组件的消费者指定的验证器,您需要将构造函数修改为:
constructor(@Self() ngControl: NgControl) {
const control = ngControl.control;
let myValidators = [Validators.required, Validators.minLength(5)];
let validators = control.validator
? [control.validator, ...myValidators]
: myValidators;
control.setValidators(validators)
control.updateValueAndValidity();
}
查看 Kara Erickson(angular 核心)在 AngularConnect 2017 上解释的整个过程。Link
您也可以保持代码不变,只需从 Injector
中获取 NgControl
,如下所示:
constructor(private injector: Injector) {
}
public ngAfterViewInit(): void {
const ngControl = this.injector.get(NgControl);
const control = ngControl.control;
// Do whatever you want with validators now:
control.setValidators(validators)
control.updateValueAndValidity();
}
您将需要使用生命周期挂钩 ngAfterViewInit
否则控件将不可用。
这样你就跳过了循环依赖的问题,你可以将 NG_VALUE_ACCESSOR
和 NG_VALIDATORS
留在 providers
数组中。
见
建议使用注射器