如何动态改变绑定的formControlName
How to dynamically change the bound formControlName
我有一个 angular 2 反应形式,有四个 formControl
和一个输入字段。我想要的是要求用户一项一项地填写信息。因此,我将 firstControlName
分配给 ngOnInit
上的 属性 调用 currentFormControlName
,并将其与模板文件中的输入字段绑定。当用户填写他的姓名时,该字段将有效,并且在提交时我会将 currentFormControlName
属性 更改为下一个 formControlName。但问题是绑定没有更新。输入字段仍然绑定到 name
。当我在输入字段中键入内容时,name
的值正在更新,而不是 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>
ngFormNameDirective
你不能那样做,因为 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
要完成您想要做的事情,您需要使用 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');
}
但是,这是一个独立的指令。
更新
您还可以使用FormControlDirective
在控件之间切换
[formControl]="form.get(currentFormControlName)"
旧答案
假设我们有以下内容
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);
}
之后我们的输入元素将管理 email
值。因此,如果我们在 input
中键入内容,它将反映在 form.email
值
中
此解决方案基于 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);
}
}
这给了我一些想法
我有一个 angular 2 反应形式,有四个 formControl
和一个输入字段。我想要的是要求用户一项一项地填写信息。因此,我将 firstControlName
分配给 ngOnInit
上的 属性 调用 currentFormControlName
,并将其与模板文件中的输入字段绑定。当用户填写他的姓名时,该字段将有效,并且在提交时我会将 currentFormControlName
属性 更改为下一个 formControlName。但问题是绑定没有更新。输入字段仍然绑定到 name
。当我在输入字段中键入内容时,name
的值正在更新,而不是 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>
ngFormNameDirective
你不能那样做,因为 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
要完成您想要做的事情,您需要使用 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');
}
但是,这是一个独立的指令。
更新
您还可以使用FormControlDirective
在控件之间切换
[formControl]="form.get(currentFormControlName)"
旧答案
假设我们有以下内容
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);
}
之后我们的输入元素将管理 email
值。因此,如果我们在 input
中键入内容,它将反映在 form.email
值
此解决方案基于 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);
}
}
这给了我一些想法