我有一个输入组件customInput
,它创建了一个经典的输入字段,并为它添加了一些布局趣味,没有额外的逻辑。
我想给它传递一个formControl,将它绑定到它包含的输入。
应该这样使用:
<form [formGroup]="form">
<custom-input [formControl]="form.controls['control']"></custom-input>
</form>
内部自定义输入:
export class HidInputFieldComponent {
@Input() formControl: AbstractControl
...
}
<div class="container">
<input [formControl]="formControl"/>
<label>label</label>
</div>
现在,当我初始化组件时,我得到
没有指定名称的表单控件的值访问器
在我的组件构造函数中记录控件,它是未定义的。
我做错了吗?还是没有办法绕过ControlValueAccessor
?由于我实际上并没有构建自定义控件(我仍然使用经典输入(,这似乎是极端的
您不需要导入ControlValueAccessor或任何类似的东西就可以实现这一点。
您所需要做的就是将FormControl对象传递给您的子组件,如下所示:
<form [formGroup]="form">
<custom-input [control]="form.controls['theControlName']">
</custom-input>
</form>
这意味着你的自定义输入组件应该是这样的:
import {Component, Input} from '@angular/core';
import {FormControl} from '@angular/forms';
@Component({
selector: 'custom-input',
templateUrl: './input.component.html',
styleUrls: ['./input.component.scss']
})
export class InputComponent {
@Input() control: FormControl;
}
模板:
<input [formControl]="control">
就是这样。
如果您实现这样的自定义输入,则不必将父窗体组带入子组件逻辑,这在那里是完全没有必要的(除非您需要对它或窗体控件的其他部分进行一些操作(。
此外,将FormControl对象传递给自定义输入将使您可以访问它的属性,而无需引用FormGroup,然后获取特定的控件,因为这是在父组件上完成的工作。
我希望这个解决方案有助于简化许多人的工作,因为制作这种自定义控件是很常见的。
[control]
,在使用自定义组件时需要始终记住。
Plus,它绑定到直接工作到ReactiveFormsModule
,因为它只接受FormControl
实例。
在我看来,更好的方法是实现ControlValueAccessor
接口,但要利用一些变通方法来避免重复控制处理:
export const NOOP_VALUE_ACCESSOR: ControlValueAccessor = {
writeValue(): void {},
registerOnChange(): void {},
registerOnTouched(): void {}
};
并在包装表单控件的组件中使用NOOP_VALUE_ACCESSOR
@Component({
selector: "wrapped-input",
template: `
<mat-form-field class="example-full-width">
<mat-label>Wrapped input</mat-label>
<!--We pass NgControl to regular MatInput -->
<input matInput [formControl]="ngControl.control" />
</mat-form-field>
`
})
export class WrappedInput {
constructor(@Self() @Optional() public ngControl: NgControl) {
if (this.ngControl) {
// Note: we provide the value accessor through here, instead of
// the `providers` to avoid running into a circular import.
// And we use NOOP_VALUE_ACCESSOR so WrappedInput don't do anything with NgControl
this.ngControl.valueAccessor = NOOP_VALUE_ACCESSOR;
}
}
}
这样Angular就会认为WrappedInput
的工作方式与实现ControlValueAccessor
接口的任何其他组件(例如MatInput
(类似。
另外,它将同时适用于ReactiveFormsModule
和常规FormsModule
。
WrappedInput
可以这样使用:
<wrapped-input [formControl]="sourceControl"></wrapped-input>
以下是您可以玩的完整工作堆叠:https://stackblitz.com/edit/angular-wrapped-form-control-example?file=src/app/app.ts
使用FormGroupDirective
此指令接受现有的FormGroup实例。那就好了使用此FormGroup实例匹配任何子FormControl、FormGroup、,和FormArray实例到子FormControlName、FormGroupName和FormArrayName指令。
这样做,您可以从父访问子窗体控件
@Component({
selector: 'app-custom-input',
templateUrl: './custom-input.html',
viewProviders:[{ provide: ControlContainer, useExisting: FormGroupDirective}]
})
export class HidInputFieldComponent {
constructor(private fcd:FormGroupDirective) {
}
ngOnInit() {
this.fcd.form.addControl('formControl',new FormControl(''));
}
}
<div class="container">
<input [formControl]="formControl"/>
<label>label</label>
</div>
我知道我参加聚会迟到了,但我偶然发现了这个问题,也有同样的问题,所以我希望这能对未来的人有所帮助。
在我的案例中,将@Input() formControl: FormControl
重命名为@Input() control: FormControl
修复了错误。
在TS文件中为自己创建一个自定义的getCtrl函数:
getCtrl(name: string): FormControl {
const ctrl = this.form.get(name) as FormControl;
if (!ctrl) throw 'Missing Form Control for ' + name;
return ctrl;
}
然后在模板中多次调用它:
<div>
<app-form-control
[control]="getCtrl('language')"
></app-form-control>
</div>
您也可以尝试实现ControlValueAccessor接口类。
@Component({
selector: 'app-custom-input',
templateUrl: './app-custom-input.component.html'
providers: [
{
provide: NG_VALUE_ACCESSOR,
multi: true,
useExisting: forwardRef(() => HidInputFieldComponent)
}
]
})
export class HidInputFieldComponent implements OnInit, ControlValueAccessor {
@Output() setDropdownEvent: EventEmitter<any> = new EventEmitter();
ngOnInit() {}
writeValue(value: any) {}
propagateChange(time: any) {
console.log(time);
}
registerOnChange(fn) {
this.propagateChange = fn;
}
registerOnTouched() {}
}