Angular 如何在自定义控件组件中触摸内部控件?
How to touch inner control in custom control component in Angular?
我有一个带有我自己的自定义控件组件的表单:
@Component({
selector: "my-app",
template: `
<form [formGroup]="form">
<app-custom-control formControlName="customControl"></app-custom-control>
</form>
<button (click)="touch()">
Touch!
</button>
`,
styleUrls: ["./app.component.css"]
})
export class AppComponent {
form: FormGroup;
constructor(private fb: FormBuilder) {}
ngOnInit() {
this.form = this.fb.group({
customControl: "1"
});
}
touch() {
this.form.markAllAsTouched();
}
}
我的自定义控件组件内部有另一个自定义控件组件(在我的真实应用程序中需要它,因为外部控件组件有两种模式 - 读取和编辑):
@Component({
selector: "app-custom-control",
template: `
<ng-select [ngModel]="value" [items]="items"></ng-select>
`,
styleUrls: ["./custom-control.component.css"],
providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: CustomControlComponent,
multi: true
}
]
})
export class CustomControlComponent implements ControlValueAccessor, OnInit {
items = ["1", "2"];
value = null;
onChange = (value: any) => {};
onTouched = () => {};
constructor() {}
registerOnChange(fn: any) {
this.onChange = fn;
}
registerOnTouched(fn: () => {}): void {
this.onTouched = fn;
}
writeValue(outsideValue: number) {
this.value = outsideValue;
}
}
可以将 NG_VALIDATORS
添加到 CustomControlComponent
并实现组件的验证方式(它可以只提升 ng-select 错误)。但是我真的不知道在包装表单的组件中执行 this.form.markAllAsTouched()
时如何触摸内部组件 (ng-select)。
我尝试在 ngDoCheck
生命周期方法中进行操作,但它似乎运行了太多次,这是不可接受的解决方案。
github中有几个相关问题:
您可以为 ControlValueAccessor 控件(outerControl
) 和内部 NgModel 控件(innerControl
) 获取 NgControl:
自定义-control.component.ts
export class CustomControlComponent implements ControlValueAccessor, AfterViewInit {
@ViewChild(NgControl) innerNgControl: NgControl;
constructor(private inj: Injector) {}
...
ngAfterViewInit() {
const outerControl = this.inj.get(NgControl).control;
...
}
}
然后你可以使用这个技巧将触摸状态绕过内部控制:
const prevMarkAsTouched = outerControl.markAsTouched;
outerControl.markAsTouched = (...args: any) => {
this.innerNgControl.control.markAsTouched();
prevMarkAsTouched.bind(outerControl)(...args);
};
我有一个带有我自己的自定义控件组件的表单:
@Component({
selector: "my-app",
template: `
<form [formGroup]="form">
<app-custom-control formControlName="customControl"></app-custom-control>
</form>
<button (click)="touch()">
Touch!
</button>
`,
styleUrls: ["./app.component.css"]
})
export class AppComponent {
form: FormGroup;
constructor(private fb: FormBuilder) {}
ngOnInit() {
this.form = this.fb.group({
customControl: "1"
});
}
touch() {
this.form.markAllAsTouched();
}
}
我的自定义控件组件内部有另一个自定义控件组件(在我的真实应用程序中需要它,因为外部控件组件有两种模式 - 读取和编辑):
@Component({
selector: "app-custom-control",
template: `
<ng-select [ngModel]="value" [items]="items"></ng-select>
`,
styleUrls: ["./custom-control.component.css"],
providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: CustomControlComponent,
multi: true
}
]
})
export class CustomControlComponent implements ControlValueAccessor, OnInit {
items = ["1", "2"];
value = null;
onChange = (value: any) => {};
onTouched = () => {};
constructor() {}
registerOnChange(fn: any) {
this.onChange = fn;
}
registerOnTouched(fn: () => {}): void {
this.onTouched = fn;
}
writeValue(outsideValue: number) {
this.value = outsideValue;
}
}
可以将 NG_VALIDATORS
添加到 CustomControlComponent
并实现组件的验证方式(它可以只提升 ng-select 错误)。但是我真的不知道在包装表单的组件中执行 this.form.markAllAsTouched()
时如何触摸内部组件 (ng-select)。
我尝试在 ngDoCheck
生命周期方法中进行操作,但它似乎运行了太多次,这是不可接受的解决方案。
github中有几个相关问题:
您可以为 ControlValueAccessor 控件(outerControl
) 和内部 NgModel 控件(innerControl
) 获取 NgControl:
自定义-control.component.ts
export class CustomControlComponent implements ControlValueAccessor, AfterViewInit {
@ViewChild(NgControl) innerNgControl: NgControl;
constructor(private inj: Injector) {}
...
ngAfterViewInit() {
const outerControl = this.inj.get(NgControl).control;
...
}
}
然后你可以使用这个技巧将触摸状态绕过内部控制:
const prevMarkAsTouched = outerControl.markAsTouched;
outerControl.markAsTouched = (...args: any) => {
this.innerNgControl.control.markAsTouched();
prevMarkAsTouched.bind(outerControl)(...args);
};