关于 javascript:Angular 4 – Reactive Forms 启用/禁用不起作用

Angular 4 - Reactive Forms enable/disable not working

我在我的应用程序中启用和禁用表单控件时遇到问题。这可能是因为表单在异步上下文中被启用/禁用。

代码如下。

user.component.html

1
2
3
4
<form [formGroup]="form">
    <input type="text" id="name" formControlName="name" />
    <input type="text" id="age" formControlName="age" />
</form>

user.component.ts

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
ngOnInit() {

     this._route.queryParams.subscribe(params => {
            getUser(params.userId).subscribe(user => {
                 this._buildForm(user);
            })
     });
}

private _buildForm(user){
    this.form = _fb.group({
        name: [{value: user.name, disabled: user.someCondition}, Validators.required],
        age: [{value: user.age, disabled: user.anotherCondition}, Validators.required]
    })
}

当用户第一次在参数更改时加载时,控件会根据其相关条件启用/禁用。当参数随后发生变化时,控件的状态保持不变,尽管值设置得当。

我尝试了不同的方法来解决这个问题,但没有任何帮助。例如,我在 _buildForm 方法的末尾尝试了以下操作。

1
2
3
this.form.disable() //Doesn't do anything

this.form.controls.name.disable(); //Doesn't help

按预期工作的一件事是以下(但这不是必需的)。

1
2
<button (click)="form.disable()" value="Disable Form" />
<button (click)="form.enable()" value="Enable Form" />

我的感觉是问题在于 _buildForm() 是从异步上下文(订阅方法)中调用的事实。

我该如何解决这个问题?

更新

请注意,Observable 订阅是基于如下导航触发的。

1
2
3
4
this._router.navigate([], {
   relativeTo: this._route,
   queryParams: {userId: 10}
})

更新 2
https://angular-cvf1fp.stackblitz.io

这是理解我的问题的一种更简单的方法


你只需要启用/禁用表单控制的方法。

这里是 stackblitz 的例子。效果很好。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: [ './app.component.css' ]
})
export class AppComponent  {
  group;
  isDisabled = true;

  constructor(fb: FormBuilder) {
    this.group = fb.group({
      stuff: fb.control({value: 'stuff', disabled: this.isDisabled})
    });
  }

  toggle() {
    this.isDisabled = !this.isDisabled;

    this.group.controls.stuff[this.isDisabled ? 'enable' : 'disable']();
  }
}


  • formGroup 直接在 ngOnit 中创建,默认情况下禁用控件,因此您确定它存在而无需担心异步问题。
  • this._route.queryParams.subscribe(...) 中,您可以使用 this.form.setValue({//set all control values})this.form.patchValue({//set individual controls}) 根据需要/一旦可用来更新各个控件。
  • conditionsomeOtherCondition 使用组件实例变量(如果您想将数据模型与表单模型分开,则使用一个整体的 user 对象 - 它们不必相同)。将这些初始化为"false",并引用它们来启用/禁用 formGroup 创建中的控件。一旦用户数据到位,您还可以在同一 .subscribe() 块中更新这些变量,而不是等待直接访问 user 数据模型。

这样,您的控件和 formGroup 就会存在并被禁用,直到异步数据可用。


你是对的。订阅只触发一次,因此在提交表单后,用户实体不再更改。为此,请在表单提交中添加一个事件处理程序。

user.component.html

1
2
3
4
<form [formGroup]="form" (submit)="_updateForm()">
    <input type="text" id="name" fromControlName="name" />
    <input type="text" id="age" fromControlName="age" />
</form>

user.component.ts

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
private userId: any;


ngOnInit() {
    this._route.queryParams.subscribe(params => {
        this.userId = params.userId;
        this._updateForm();
    });
}

private _buildForm(user){
    this.form = _fb.group({
        name: [{value: user.name, disabled: user.someCondition}, Validators.required],
        age: [{value: user.age, disabled: user.anotherCondition}, Validators.required]
    });
}

// The update function has to be public to be called inside your template
public _updateForm(){
    getUser(this.userId).subscribe(user => {
        this._buildForm(user);
    });
}


1
2
3
4
<form [formGroup]="form">
    <input type="text" id="name" fromControlName="name" />
    <input type="text" id="age" fromControlName="age" />
</form>

你看到这里有错字吗?fromControlName 应该是 formControlName
之后,切换将起作用;)

https://angular-rivxs5.stackblitz.io