问题描述
我正在看这个问题,试图弄清楚如何扩展 FormControlDirective:尝试扩展 FormControlDirective 以实现我自己的 FormControl 指令导致绑定错误.
I'm looking at this question, trying to figure out how to extend FormControlDirective: Attempting to extend FormControlDirective to implement my own FormControl directive results in faulty binding.
有一个答案,但我不确定是什么意思:
There is an answer, but I'm not sure what is meant by:
formControl
\ formControlName
选择器出现在另外一个地方 - 价值存取器.为了您的指令工作,您应该实现所有默认值hybridFormControl
指令的访问器(在内置指令的模式).
这是我的代码:
export const formControlBinding: any = {
provide: NgControl,
useExisting: forwardRef(() => ControlDirective)
};
@Directive({
selector: '[appControl]',
providers: [formControlBinding],
exportAs: 'ngForm'
})
export class ControlDirective extends FormControlDirective implements OnInit {
constructor(
@Optional() @Self() @Inject(NG_VALIDATORS) validators: Array<Validator|ValidatorFn>,
@Optional() @Self() @Inject(NG_ASYNC_VALIDATORS) asyncValidators: Array<AsyncValidator|AsyncValidatorFn>,
@Optional() @Self() @Inject(NG_VALUE_ACCESSOR) valueAccessors: ControlValueAccessor[],
public renderer: Renderer2,
public hostElement: ElementRef,
) {
super(validators, asyncValidators, valueAccessors);
}
@Input() set appControl(form: FormControl) {
console.log(form);
this.form = form;
}
}
这与@ronif 在他的问题中的 Plunker 非常相似.set appControl
确实运行,即使我传递了一个像 <input type="text" class="form-control" appControl="firstName">
的值,并且 FormControlDirective._rawValidators
似乎总是一个空数组,即使 FormGroup
与标准的 FormControlDirective
一起使用.
It is very similar to @ronif's Plunker from his question. set appControl
does run, even though I'm passing a value like <input type="text" class="form-control" appControl="firstName">
, and FormControlDirective._rawValidators
seems to always be an empty array, even though the FormGroup
works with the standard FormControlDirective
.
我将如何实现所有默认值访问器"?
How would I go about 'implementing all default value accessors'?
推荐答案
如果其他人遇到这样的情况,这里是我想出的解决方案.我想从子表单控件元素动态创建表单控件模型.这样我就不必编写包含大量表单控件字段的初始模型,同时仍能从反应式表单模型中受益.这是如何扩展 FormControlName 类:
In case anyone else runs into something like this, here is the solution I came up with. I wanted to dynamically create a form control model from the child form control element. This is so I didn't have to write an initial model with tons of form control fields while still getting the benefit of the reactive forms model. This is how to extend the FormControlName class:
@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;
}
}
你会使用这个新的混合指令,如:
And you would use this new hybrid directive like:
@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({});
}
}
如果要传递验证器,则需要修改 this.formGroup.registerControl(name, this.fb.control(''));
代码行.我还没有验证这一点,但希望这可以帮助遇到这个问题的其他人.
You will need to modify this.formGroup.registerControl(name, this.fb.control(''));
line of code if you want to pass validators. I haven't verified this, but hopefully this helps someone else who runs across this question.
这篇关于在 Angular 2+ 中扩展 FormControlDirective的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!