我的Angular应用程序中有一个自定义表单控件组件,它实现了ControlValueAccessor
接口。
但是,我想访问与我的组件关联的FormControl
实例。我使用FormBuilder
的反应式表单,并使用formControlName
属性提供表单控件。
那么,如何从我的自定义表单组件中访问FormControl
实例?
答案 0 :(得分:41)
此解决方案诞生于Angular存储库中的the discussion。如果您对此问题感兴趣,请务必阅读或更好地参与。
我研究了FormControlName
指令的代码,这激励我编写以下解决方案:
@Component({
selector: 'my-custom-form-component',
templateUrl: './custom-form-component.html',
providers: [{
provide: NG_VALUE_ACCESSOR,
useExisting: CustomFormComponent,
multi: true
}]
})
export class CustomFormComponent implements ControlValueAccessor, OnInit {
@Input() formControlName: string;
private control: AbstractControl;
constructor (
@Optional() @Host() @SkipSelf()
private controlContainer: ControlContainer
) {
}
ngOnInit () {
if (this.controlContainer) {
if (this.formControlName) {
this.control = this.controlContainer.control.get(this.formControlName);
} else {
console.warn('Missing FormControlName directive from host element of the component');
}
} else {
console.warn('Can\'t find parent FormGroup directive');
}
}
}
我正在将父FormGroup
注入组件,然后使用通过FormControl
绑定获得的控件名称从中获取特定的formControlName
。
但是,请注意,此解决方案专门针对在host元素上使用FormControlName
指令的用例而定制。它在其他情况下不起作用。为此,您需要添加一些额外的逻辑。如果您认为这应该由Angular解决,请务必访问the discussion。
答案 1 :(得分:21)
通过const mousePositionControl = new MousePosition({
coordinateFormat: createStringXY(4),
projection: 'EPSG:4326',
className: 'custom-mouse-position',
target: document.getElementById('mouse-position'),
undefinedHTML: ' '
});
const map = new Map({
controls: defaultControls({
attributionOptions: {
collapsible: false
}
}).extend([mousePositionControl]),
layers: [
new TileLayer({
source: new OSM()
})
],
target: 'map',
view: new View({
center: [0, 0],
zoom: 2
})
});
指令绑定时,使用formControlName
作为输入参数是无效的。
这是一种无需任何输入参数即可双向工作的解决方案。
[formControl]
答案 2 :(得分:6)
基于先前的答案和评论中发现的documentation,这是我认为是基于ControlValueAccessor
的组件的最干净的解决方案。
// No FormControl is passed as input to MyComponent
<my-component formControlName="myField"></my-component>
export class MyComponent implements AfterViewInit, ControlValueAccessor {
constructor(@Optional() @Self() public ngControl: NgControl) {
if (ngControl != null) {
// Setting the value accessor directly (instead of using
// the providers) to avoid running into a circular import.
ngControl.valueAccessor = this;
}
}
ngAfterContentInit(): void {
const control = this.ngControl && this.ngControl.control;
if (control) {
// FormControl should be available here
}
}
}
答案 3 :(得分:4)
由于@Ritesh已在评论中写入,您可以将表单控件作为输入绑定传递:
<my-custom-form-component [control]="myForm.get('myField')" formControlName="myField">
</my-custom-form-component>
然后您可以在自定义表单组件中获取表单控件实例,如下所示:
@Input() control: FormControl;
答案 4 :(得分:1)
对于任何在2019年使用Angular 6/7 +来此访问的人,此答案中所描述的解决方案均不会引发弃用警告:
https://stackoverflow.com/a/56061527/134120
有关更多详细信息,请观看this presentation,如上所述。
答案 5 :(得分:0)
这里是接受的答案的简化/清理版本,适用于FormControlName和FormControl输入:
export class CustomFormComponent implements ControlValueAccessor, OnInit {
@Input() formControl: FormControl;
@Input() formControlName: string;
// get ahold of FormControl instance no matter formControl or formControlName is given.
// If formControlName is given, then controlContainer.control is the parent FormGroup/FormArray instance.
get control() {
return this.formControl || this.controlContainer.control.get(this.formControlName);
}
constructor(private controlContainer: ControlContainer) { }
}