如何在Angular的自定义控件组件中触摸内部控件?
Posted
技术标签:
【中文标题】如何在Angular的自定义控件组件中触摸内部控件?【英文标题】:How to touch inner control in custom control component in Angular? 【发布时间】:2021-02-22 18:39:12 【问题描述】:我有一个带有我自己的自定义控件组件的表单:
@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
生命周期方法中进行操作,但它似乎运行了太多次,这是不可接受的解决方案。
游乐场:https://stackblitz.com/edit/angular-ivy-u3kdfj
【问题讨论】:
【参考方案1】:在 github 中有几个相关的问题:
https://github.com/angular/angular/issues/10887 https://github.com/angular/angular/issues/17736您可以做的是为 ControlValueAccessor 控件(outerControl
)和内部 NgModel 控件(innerControl
)获取 NgControl:
custom-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);
;
Forked Stackblitz
【讨论】:
以上是关于如何在Angular的自定义控件组件中触摸内部控件?的主要内容,如果未能解决你的问题,请参考以下文章