I have an angular 2 reactive form with four formControl
s and only one input field. What I want is to ask the user to fill up the infos one by on. So, I'm assigning the firstControlName
to a property call currentFormControlName
on ngOnInit
and binding it with the input field in template file. When the user fill up his name the field will be valid and on submit I'll change the currentFormControlName
property to next formControlName. But the problem is the binding isn't updating. The input field is still bonded to name
. When I type something on the input field the value of name
is updating not email
.
app.component.ts
ngOnInit() {
this.form = this.builder.group({
'name': ['', Validator.required],
'email': ['', Validator.email],
'phone': ['', Validator.required],
'password': ['', Validator.required],
});
this.currentFormControlName = 'name';
}
submit() {
this.currentFormControlName = 'email'; // Setting it manually just for the demo of this question.
}
app.component.html
<form [formGroup]="form">
<input type="text" [formControlName]="currentFormControlName">
<input type="submit" (click)="submit()">
</form>
答案 0 :(得分:2)
假设我们有以下
<强> template.html 强>
<form [formGroup]="form" #formDir="ngForm">
<input type="text" #controlDir [formControlName]="currentFormControlName">
<input type="submit" (click)="submit()">
</form>
<pre>{{ form.value | json }}</pre>
点击提交按钮后,我们可以更改currentFormControlName
并使用新名称注册控件,如
<强> component.ts 强>
form: FormGroup;
@ViewChild('formDir') formDir: FormGroupDirective;
@ViewChild('controlDir', { read: FormControlName }) controlDir: FormControlName;
currentFormControlName: string;
constructor(private builder: FormBuilder) {}
ngOnInit() {
this.form = this.builder.group({
'name': ['', Validators.required],
'email': ['', Validators.email],
'phone': ['', Validators.required],
'password': ['', Validators.required],
});
this.currentFormControlName = 'name';
}
submit() {
this.formDir.removeControl(this.controlDir);
this.controlDir.name = this.currentFormControlName = 'email'
this.formDir.addControl(this.controlDir);
}
之后我们的input元素将管理email
值。因此,如果我们在input
中输入内容,则会反映在form.email
值
<强> Plunker Example 强>
此解决方案基于FormControlName source code
ngOnChanges(changes: SimpleChanges) {
if (!this._added) this._setUpControl();
if (isPropertyUpdated(changes, this.viewModel)) {
this.viewModel = this.model;
this.formDirective.updateModel(this, this.model);
}
}
我们可以看到这个指令只控制一次控制。但它也有以下ngOnDestroy挂钩
ngOnDestroy(): void {
if (this.formDirective) {
this.formDirective.removeControl(this);
}
}
给了我一些想法
<强>更新强>
您还可以使用FormControlDirective
在控件之间切换
[formControl]="form.get(currentFormControlName)"
<强> Plunker Example 强>
答案 1 :(得分:1)
您不能这样做,因为ngFormControlName
指令只在此使用@Input() name
一次:
@Directive({selector: '[formControlName]'...})
export class FormControlName extends ... {
@Input('formControlName') name: string;
ngOnChanges(changes: SimpleChanges) {
if (!this._added) this._setUpControl(); <------------ here
if (isPropertyUpdated(changes, this.viewModel)) {
每次后续更改this._added
将为true
。您在ngOnChanges
中可以看到的下一项检查是isPropertyUpdated
,它不检查name
输入更改,只检查model
输入:
export function isPropertyUpdated(changes: {[key: string]: any}, viewModel: any): boolean {
if (!changes.hasOwnProperty('model')) return false;
const change = changes['model'];
要执行您尝试执行的操作,您需要使用ngFormDirective
检查控件是否已更新:
export class FormControlDirective extends NgControl implements OnChanges {
viewModel: any;
@Input('formControl') form: FormControl;
ngOnChanges(changes: SimpleChanges): void {
if (this._isControlChanged(changes)) {
private _isControlChanged(changes: {[key: string]: any}): boolean {
return changes.hasOwnProperty('form');
}
但是,这是一个独立的指令。