我不明白,应如何在angular2中以模型驱动的形式处理复选框组。

该模型具有一个属性languages,我将其实例化为:

this.model = {
  languages: []
};

使用FormBuilder创建表单:
this.modelForm = this.formBuilder.group({
  'languages': [model.languages, Validators.required],
});

和模板:
<div *ngFor="let language of translateService.get('languages') | async | key_value">
  <input type="checkbox" name="languages[]" formControlName="languages" value="{{ language.key }}" id="language_{{ language.key }}">
  <label attr.for="language_{{ language.key }}">{{ language.value }}</label>
</div>

需要div来进行样式设置(自定义复选框),很明显key_value使循环中可以使用该语言的键和值。

第一个问题来自验证。如果选中并取消选中一个复选框(并且没有选中其他复选框),则输入仍然有效-有点奇怪。

第二个问题与值有关,如果检查两种或两种以上的语言,则值为true,否则为false

然后还有languages的初始值的第三个问题,它只是一个空数组,但是使所有复选框都被初始检查(如果将初始值设置为string则不会发生),尽管我无法发现任何checked DOM中的属性。

我正在使用最新的 ionic beta(2.0.0-beta.10),该版本使用angular/core版本2.0.0-rc.4和angular/forms版本0.2.0。

那么,有没有关于如何使用复选框组的指南?有什么建议或想法吗?

最佳答案


我注意到,如果languages的值是一个空数组,它将通过Validations.required检查。

我认为问题是您将多个控件绑定(bind)到单个FormControl的方式,我认为需要涉及FormArray,可能与存储您的复选框数组结果的另一个FormControl有关。

当然,我在实现它时遇到了麻烦,我将首先发布该实现,然后再发布一些注意事项。您可以在https://plnkr.co/edit/hFU904?p=preview上查看它的运行情况

@Component({
  template: `
    <template [ngIf]="loading">
      Loading languages...
    </template>
    <template [ngIf]="!loading">
      <form [formGroup]="modelForm">
        <div [formArrayName]="'languages'" [class.invalid]="!modelForm.controls.selectedLanguages.valid">
          <div *ngFor="let language of modelForm.controls.languages.controls; let i = index;" [formGroup]="language">
            <input type="checkbox" formControlName="checked" id="language_{{ language.controls.key.value }}">
            <label attr.for="language_{{ language.controls.key.value }}">{{ language.controls.value.value }}</label>
          </div>
        </div>
        <hr>
        <pre>{{modelForm.controls.selectedLanguages.value | json}}</pre>
      </form>
    </template>
  `
})
export class AppComponent {
    loading:boolean = true;
    modelForm:FormGroup;
    languages:LanguageKeyValues[];

    constructor(public formBuilder:FormBuilder){
    }

    ngOnInit() {

      this.translateService.get('languages').subscribe((languages:LanguageKeyValues[]) => {

        let languagesControlArray = new FormArray(languages.map((l) => {
          return new FormGroup({
            key: new FormControl(l.key),
            value: new FormControl(l.value),
            checked: new FormControl(false),
          });
        }));

        this.modelForm = new FormGroup({
          languages: languagesControlArray,
          selectedLanguages: new FormControl(this.mapLanguages(languagesControlArray.value), Validators.required)
        });

        languagesControlArray.valueChanges.subscribe((v) => {
          this.modelForm.controls.selectedLanguages.setValue(this.mapLanguages(v));
        });

        this.loading = false;
      });
    }

    mapLanguages(languages) {
      let selectedLanguages = languages.filter((l) => l.checked).map((l) => l.key);
      return selectedLanguages.length ? selectedLanguages : null;
    }
}
这里的主要区别是,我将您的model.languages合并到了modelForm中,现在在模板中的modelForm.languages FormArray上重复。modelForm.languages已成为modelForm.selectedLanguages,现在是基于modelForm.languages中检查的值的计算值。如果未选择任何内容,则modelForm.selectedLanguages设置为null,以使验证失败。
直到语言可用,modelForm才会实例化,这主要是个人喜好,我确定您可以将languagesselectedLanguages异步附加到modelForm,但是它简化了同步构造它的过程。
我取出了translateService.get('languages') | async,注意到在模板中调用此函数时,出现了一些奇怪的行为,并且无论如何,我还是更喜欢在组件中展开可观察对象,以捕获加载/错误状态。
它不像某些 native 复选框数组形式控件那样优雅,但它干净且非常灵活。退房the plunker,如果您有任何疑问,请通知我!

09-26 11:45