Angular2中的复选框组处理和验证

时间:2016-09-24 09:22:44

标签: angular ionic-framework ionic2 angular2-forms

我不知道如何在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的初始值,它只是一个空数组,但会导致最初检查所有复选框(如果初始值设置为{,则不会发生) {1}}),虽然我无法在DOM中发现任何string属性。

我正在使用最新的离子测试版(2.0.0-beta.10),它使用角度/核心版本2.0.0-rc.4和角度/形式版本0.2.0。

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

2 个答案:

答案 0 :(得分:6)

  

第一个问题来自验证。如果检查并取消选中一个复选框(并且未选中其他复选框),则输入仍然有效 - 不知何故很奇怪。

我注意到如果languages的值为空数组,则会通过Validations.required检查。

  

第二个问题是值,如果检查了两种以上的语言则为true,否则为false。

     

然后第三个问题是语言的初始值只是一个空数组,但会导致所有复选框最初被检查(如果初始值设置为字符串则不会发生),尽管我不能发现DOM中的任何已检查属性。

我认为问题在于您将多个控件绑定到单个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,我注意到在模板中调用了这个函数的一些奇怪的行为,我更喜欢在组件中展开我的observable,以捕获加载/错误状态。

它不像一些原生复选框数组表单控件那样优雅,但它干净且非常灵活。查看the plunker,如果您有任何疑问,请与我们联系!

答案 1 :(得分:2)

如果选中一个复选框然后取消选中它,即使取消选中,FormControl仍会将其显示为有效。可能会发生它只需要真值和假值。您可以尝试这个代码示例,因为它对我有用 -

                             mustBeChecked(control: FormControl): {[key: string]: string} {
                              if (!control.value) {
                              return {mustBeCheckedError: 'Must be checked'};
                               } else {
                                       return null;
                                      }
                                }

您也可以参考此plunker

此处存在一个未解决的问题,即在更改值之前触发click事件。请参阅github链接here。希望它可以帮助您。

多个复选框有不同的解决方法,例如使用

event.target.checked

而不是模型中的值。

你可以像在这个样本中那样使用它 -

           <input type="checkbox"  
                (change)="expression && expression.Option1=$event.target.checked ? true : undefiend"
                 [ngModel]="expression?.Option1">
           <input type="checkbox"  
                (change)="expression && expression.Option2=$event.target.checked ? true : undefiend"
                 [ngModel]="expression?.Option2">