[英]Angular ControlValueAccessor how to transfert the invalid status?
[英]How to pass NgControl status to child component in Angular, implementing ControlValueAccessor?
提供
{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => TestingComponent),
multi: true
}
注入的NgControl
constructor(@Self() @Optional() public control: NgControl) {
this.control && (this.control.valueAccessor = this);
}
但是这里缺少什么吗?
尽管@Eliseo的答案很有解释性,但还是有一个补充...如果要同时使用外部验证器和内部验证器,则必须相应地设置父级NgControl验证器。 此外,如果您想使用验证,则需要使用ngDoCheck生命周期挂钩来处理NgControl触摸状态,因为以下是我的最终解决方案
@Component({
selector: 'app-testing',
templateUrl: 'testing.component.html'
})
export class TestingComponent implements ControlValueAccessor, DoCheck, AfterViewInit {
@Input()
public required: boolean;
@ViewChild('input', { read: NgControl })
private inputNgModel: NgModel;
public value: number;
public ngControlTouched: boolean;
constructor(@Optional() @Self() public ngControl: NgControl) {
if (this.ngControl != null) this.ngControl.valueAccessor = this;
}
ngDoCheck() {
if (this.ngControlTouched !== this.ngControl.touched) {
this.ngControlTouched = this.ngControl.touched;
}
}
ngAfterViewInit() {
// Setting ngModel validators to parent NgControl
this.ngControl.control.setValidators(this.inputNgModel.validator);
}
/**
* ControlValueAccessor Implementation
* Methods below
*/
writeValue(value: number): void {
this.value = value;
this.onChange(this.value);
}
onChange: (_: any) => void = (_: any) => {};
onTouched: () => void = () => {};
registerOnChange(fn: any): void {
this.onChange = fn;
}
registerOnTouched(fn: any): void {
this.onTouched = fn;
}
}
// Template
<input
#input="ngModel"
type="text"
class="form-control"
[class.is-invalid]="input.invalid && (input.dirty || input.touched || ngControlTouched)"
[(ngModel)]="value"
(ngModelChange)="onChange(value)"
(blur)="onTouched()"
[required]="required"
/>
// Usage
<app-testing [(ngModel)]="propertyDetails.whatThreeWords" name="testing" required></app-testing>
您有两个选择:
注入NgControl,为此,您需要删除提供程序并以如下方式构造构造函数
constructor(public control:NgControl){
if (this.control != null) {
this.control.valueAccessor = this;
}
}
然后,您可以像
<input [ngClass]="{'ng-invalid':control.invalid,'ng-valid':control.valid...}">
或将customFormControl的类复制到输入。
您的输入就像
<input [ngClass]="class">
如果在自定义窗体控件的构造函数中导入ElementRef
constructor(private el:ElementRef){}
并创建一个函数“ copyClass”
copyClass()
{
setTimeout(()=>{
this.class=this.elementRef.nativeElement.getAttribute('class')
})
}
您可以在writeValue,Change和OnTouched中调用此函数。
我能想象到的最简单的例子是在这个堆叠闪电战中
注意:如果您的问题是您在组件中使用了材质角度,则技术使用了customErrorMatcher,请查看官方文档 ,如果您想在stackoverflow中获得此答案
更新另一个方法是将相同的验证器设置为输入。 为此,我们使用viewChild来获取输入,并且在ngAfterViewInit中等于验证器。
@ViewChild('input',{static:false,read:NgControl}) input
ngAfterViewInit()
{
if (this.control != null) {
this.input.control.setValidators(this.control.control.validator)
}
}
看到另一个堆叠闪电战
在最后一次更新时,如果我们想在控件内出现自定义错误,可以使用validate函数来获取控件,而不是将其注入构造函数中。 组件变得像
@Component({
...
providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => CustomFormControlComponent),
multi: true
},
{
provide: NG_VALIDATORS,
useExisting: forwardRef(() => CustomFormControlComponent),
multi: true,
}]
})
export class CustomFormControlComponent implements ControlValueAccessor,
Validator, AfterViewInit {
...
control:any
@ViewChild('input', { static: false, read: NgControl }) input
constructor() {
}
ngAfterViewInit() {
this.validate(null)
}
validate(control: AbstractControl): ValidationErrors | null{
if (!this.control)
this.control=control;
if (this.control && this.input)
this.input.control.setValidators(this.control.validator)
if (control.value=="qqq")
return {error:"Inner error:The value is 1"}
return null
}
新的堆叠闪电战
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.