尝试扩展 FormControlDirective 以实现我自己的 FormControl 指令导致绑定错误
Attempting to extend FormControlDirective to implement my own FormControl directive results in faulty binding
我正在尝试反转表单控件将自己注册到 FormGroup
上的方式,这样就不必
@Component({..., template: `<input [formControl]="myControl"`}
...
或
@Component({..., template: `<input [formControName]="myControlName"`}
...
我可以
@Component({..., template: `<input myFormControl`}
...
并让我的指令为我创建并添加 FormControl
。
最好用这个Plunker来解释。
将视图绑定到表单模型似乎不起作用,如您所见,更改输入不会更改表单模型值。
调试显示没有 valueAccessor
注入到构造函数中(不同于直接使用基础 FormControlDirective
class)。
如果您想知道,我的最终目标是拥有一个父级自定义组组件,该组件 @ViewChildren(MyFormDirective)
并将它们全部动态添加到它创建的表单中。
你快到了。不过还有一个窍门。该输入元素没有 DefaultValueAccessor
,因此构造函数参数填充有 null
值。
formControl
\ formControlName
选择器又出现在一处 - the value accessor。为了使您的指令起作用,您应该为 hybridFormControl
指令实现所有默认值访问器(遵循内置指令的模式)。
P.S 我认为您的指令提供者应该更正为
providers: [{
provide: NgControl, //<-- NgControl is the key
useExisting: forwardRef(() => HybridFormControlDirective)
}]
我运行遇到了同样的问题。奇怪的是没有更多关于此的 Whosebug 帖子。上面的答案对我不起作用,但这是我在有更多答案的情况下解决的方法。
@Directive({
selector: '[hybridFormControl]'
})
class HybridFormControl Directive extends FormControlName implements ControlValueAccessor, OnChanges {
@Input('hybridFormControl') name: string;
onChange;
onTouched;
constructor(
@Optional() protected formGroupDirective: FormGroupDirective,
@Optional() @Self() @Inject(NG_VALUE_ACCESSOR) valueAccessors: ControlValueAccessor[],
private fb: FormBuilder,
private renderer: Renderer2,
private element: ElementRef
) {
super(formGroupDirective, [], [], valueAccessors, null);
this.valueAccessor = this;
}
ngOnChanges(changes: SimpleChanges): void {
if (!this._registered) {
// dynamically create the form control model on the form group model.
this.formGroup = this.formGroupDirective.form;
this.formGroup.registerControl(name, this.fb.control(''));
this._registered = true;
}
// IMPORTANT - this ties your extended form control to the form control
// model on the form group model that we just created above. Take a look
// at Angular github source code.
super.ngOnChanges(changes);
}
@HostListener('input', ['$event.target.value'])
@HostListener('change', ['$event.target.value'])
onInput(value): void {
this.onChange(modelValue);
}
writeValue(value): void {
const element = this.element.nativeElement;
this.renderer.setProperty(element, 'value', value);
}
registerOnChange(fn): void {
this.onChange = fn;
}
registerOnTouched(fn): void {
this.onTouched = fn;
}
}
这个混合组件可以像这样使用:
@Component({
selector: 'app',
template: `
<form formGroup=[formGroup]>
<input type="text" hybridFormControl="myName">
</form>
`
class AppComponent {
formGroup: FormGroup
constructor(fb: FormBuilder) {
this.form = this.fb.group({});
}
}
我正在尝试反转表单控件将自己注册到 FormGroup
上的方式,这样就不必
@Component({..., template: `<input [formControl]="myControl"`}
...
或
@Component({..., template: `<input [formControName]="myControlName"`}
...
我可以
@Component({..., template: `<input myFormControl`}
...
并让我的指令为我创建并添加 FormControl
。
最好用这个Plunker来解释。
将视图绑定到表单模型似乎不起作用,如您所见,更改输入不会更改表单模型值。
调试显示没有 valueAccessor
注入到构造函数中(不同于直接使用基础 FormControlDirective
class)。
如果您想知道,我的最终目标是拥有一个父级自定义组组件,该组件 @ViewChildren(MyFormDirective)
并将它们全部动态添加到它创建的表单中。
你快到了。不过还有一个窍门。该输入元素没有 DefaultValueAccessor
,因此构造函数参数填充有 null
值。
formControl
\ formControlName
选择器又出现在一处 - the value accessor。为了使您的指令起作用,您应该为 hybridFormControl
指令实现所有默认值访问器(遵循内置指令的模式)。
P.S 我认为您的指令提供者应该更正为
providers: [{
provide: NgControl, //<-- NgControl is the key
useExisting: forwardRef(() => HybridFormControlDirective)
}]
我运行遇到了同样的问题。奇怪的是没有更多关于此的 Whosebug 帖子。上面的答案对我不起作用,但这是我在有更多答案的情况下解决的方法。
@Directive({
selector: '[hybridFormControl]'
})
class HybridFormControl Directive extends FormControlName implements ControlValueAccessor, OnChanges {
@Input('hybridFormControl') name: string;
onChange;
onTouched;
constructor(
@Optional() protected formGroupDirective: FormGroupDirective,
@Optional() @Self() @Inject(NG_VALUE_ACCESSOR) valueAccessors: ControlValueAccessor[],
private fb: FormBuilder,
private renderer: Renderer2,
private element: ElementRef
) {
super(formGroupDirective, [], [], valueAccessors, null);
this.valueAccessor = this;
}
ngOnChanges(changes: SimpleChanges): void {
if (!this._registered) {
// dynamically create the form control model on the form group model.
this.formGroup = this.formGroupDirective.form;
this.formGroup.registerControl(name, this.fb.control(''));
this._registered = true;
}
// IMPORTANT - this ties your extended form control to the form control
// model on the form group model that we just created above. Take a look
// at Angular github source code.
super.ngOnChanges(changes);
}
@HostListener('input', ['$event.target.value'])
@HostListener('change', ['$event.target.value'])
onInput(value): void {
this.onChange(modelValue);
}
writeValue(value): void {
const element = this.element.nativeElement;
this.renderer.setProperty(element, 'value', value);
}
registerOnChange(fn): void {
this.onChange = fn;
}
registerOnTouched(fn): void {
this.onTouched = fn;
}
}
这个混合组件可以像这样使用:
@Component({
selector: 'app',
template: `
<form formGroup=[formGroup]>
<input type="text" hybridFormControl="myName">
</form>
`
class AppComponent {
formGroup: FormGroup
constructor(fb: FormBuilder) {
this.form = this.fb.group({});
}
}