web-dev-qa-db-ja.com

少なくとも1つのチェックボックスが選択されていることを検証する方法は?

ここでフォームタグなしでチェックボックスの検証を行いたいです。 少なくとも1つのチェックボックスを選択する必要があります。

<div *ngFor="let item of officeLIST">
  <div *ngIf=" item.officeID == 1">
    <input #off type="checkbox" id="off" name="off" value="1" [(ngModel)]="item.checked">
    <label>{{item.officename}}</label>
  </div>

  <div *ngIf="item.officeID== 2">
    <input #off type="checkbox" id="off" name="off" value="2" [(ngModel)]="item.checked">
    <label>{{item.officename}}</label>
  </div>

  <div *ngIf="item.officeID== 3">
    <input #off type="checkbox" id="off" name="off" value="3" [(ngModel)]="item.checked">
    <label>{{item.officename}}</label>
  </div>
</div>

他のフィールドではrequiredを入力し、error | touched | validなどを行いますが、チェックボックスは単一入力ではないため、すべてのチェックボックスが必須であるため、すべてのチェックボックスにrequiredを配置することはできません。少なくともユーザーがチェックされるべきであることをユーザーに警告するためにどのように検証を行うのですか?

16
user3431310

チェックボックスグループを含むFormGroupを作成し、グループのチェックされた値を必要なバリデーターで非表示のフォームコントロールにバインドすることを検討してください。

3つのチェックボックスがあると仮定します

items = [
  {key: 'item1', text: 'value1'},      // checkbox1 (label: value1)
  {key: 'item2', text: 'value2'},      // checkbox2 (label: value2)
  {key: 'item3', text: 'value3'},      // checkbox3 (label: value3)
];

ステップ1:チェックボックスにFormArrayを定義する

let checkboxGroup = new FormArray(this.items.map(item => new FormGroup({
  id: new FormControl(item.key),      // id of checkbox(only use its value and won't show in html)
  text: new FormControl(item.text),   // text of checkbox(show its value as checkbox's label)
  checkbox: new FormControl(false)    // checkbox itself
})));

*ngForで表示しやすい

ステップ2:チェックボックスグループのステータスを保持するために必要な非表示のformControlを作成します

let hiddenControl = new FormControl(this.mapItems(checkboxGroup.value), Validators.required);
// update checkbox group's value to hidden formcontrol
checkboxGroup.valueChanges.subscribe((v) => {
  hiddenControl.setValue(this.mapItems(v));
});

非表示コントロールに必要な検証ステータスのみを考慮し、この非表示コントロールをhtmlに表示しません。

ステップ3:下のチェックボックスグループと非表示のformControlを含む最終フォームグループを作成します

this.form = new FormGroup({
  items: checkboxGroup,
  selectedItems: hiddenControl
});

Htmlテンプレート:

<form [formGroup]="form">
  <div [formArrayName]="'items'" [class.invalid]="!form.controls.selectedItems.valid">
    <div *ngFor="let control of form.controls.items.controls; let i = index;" [formGroup]="control">
      <input type="checkbox" formControlName="checkbox" id="{{ control.controls.id.value }}">
      <label attr.for="{{ control.controls.id.value }}">{{ control.controls.text.value }}</label>
    </div>
  </div>
  <div [class.invalid]="!form.controls.selectedItems.valid" *ngIf="!form.controls.selectedItems.valid">
    checkbox group is required!
  </div>
  <hr>
  <pre>{{form.controls.selectedItems.value | json}}</pre>
</form>

これを参照してください デモ

18
Pengyy

受け入れられた回答は、意図されていない方法で使用するものを悪用します。 reactive forms で、最も簡単でおそらく正しい方法は、グループ化されたチェックボックスを保持する FormGroup を使用し、少なくとも1つ(またはそれ以上)のチェックボックスをチェックするバリデーターを作成することですそのグループ内でチェックされます。

そのためには、既存のFormGroup内に別のFormGroupを作成し、それにバリデーターを添付します。

_form = new FormGroup({
    // ...more form controls...
    myCheckboxGroup: new FormGroup({
      myCheckbox1: new FormControl(false),
      myCheckbox2: new FormControl(false),
      myCheckbox3: new FormControl(false),
    }, requireCheckboxesToBeCheckedValidator()),
    // ...more form controls...
  });
_

そして、ここにバリデーターがあります。少なくともX個のチェックボックスがオンになっているかどうかを確認するためにも使用できるように作成しました。 requireCheckboxesToBeCheckedValidator(2)

_import { FormGroup, ValidatorFn } from '@angular/forms';

export function requireCheckboxesToBeCheckedValidator(minRequired = 1): ValidatorFn {
  return function validate (formGroup: FormGroup) {
    let checked = 0;

    Object.keys(formGroup.controls).forEach(key => {
      const control = formGroup.controls[key];

      if (control.value === true) {
        checked ++;
      }
    });

    if (checked < minRequired) {
      return {
        requireCheckboxesToBeChecked: true,
      };
    }

    return null;
  };
}
_

テンプレートには、チェックボックスをラップするディレクティブ ' formGroupName 'を追加することを忘れないでください。しかし、心配しないでください。コンパイラは、忘れるとエラーメッセージを表示します。その後、FormControlの場合と同じ方法で、checkbox-groupが有効かどうかを確認できます。

_<ng-container [formGroup]="form">
   <!-- ...more form controls... -->

   <div class="form-group" formGroupName="myCheckboxGroup">
      <div class="custom-control custom-checkbox">
        <input type="checkbox" class="custom-control-input" formControlName="myCheckbox1" id="myCheckbox1">
        <label class="custom-control-label" for="myCheckbox1">Check</label>
      </div>

      <div class="custom-control custom-checkbox">
        <input type="checkbox" class="custom-control-input" formControlName="myCheckbox2" id="myCheckbox2">
        <label class="custom-control-label" for="myCheckbox2">At least</label>
      </div>

      <div class="custom-control custom-checkbox">
        <input type="checkbox" class="custom-control-input" formControlName="myCheckbox3" id="myCheckbox3">
        <label class="custom-control-label" for="myCheckbox3">One</label>
      </div>

      <div class="invalid-feedback" *ngIf="form.controls['myCheckboxGroup'].errors && form.controls['myCheckboxGroup'].errors.requireCheckboxesToBeChecked">At least one checkbox is required to check</div>
    </div>

    <!-- ...more form controls... -->
  </ng-container>
_

*このテンプレートは非常に静的です。もちろん、フォームデータ(FormControlのキー、ラベル、必須など)を保持する追加の配列を使用して動的に作成し、ngFor

受け入れられた回答のような非表示のFormControlを悪用しないでください。 FormControlは、id、label、help-textなどのデータを保存するためのものではなく、名前/キーすらありません。これらすべて、およびそれ以上は、別々に保存する必要があります。オブジェクトの通常の配列によって。 FormControlは入力値のみを保持し、このクールな状態と機能をすべて提供します。

私が作成した作業例で遊ぶことができます: https://stackblitz.com/edit/angular-at-least-one-チェックボックスをオン

24
Mick

検証(クリックイベントなど)で配列を反復処理し、少なくとも1つの項目がtrueであるかどうかを確認します。

let isSelected: any = this.officeLIST.filter((item) => item.checked === true);
if(isSelected != null && isSelected.length > 0) {
 //At least one is selected
}else {
 alert("select at least one");
}
3
Nugu

私は同じ問題を抱えていましたが、これはAngular 6 FormGroupで使用することになったソリューションです。

[〜#〜] html [〜#〜]注:私はAngular素材を使用して、必要に応じて変更します。

<form [formGroup]="form">
  <mat-checkbox formControlName="checkbox1">First Checkbox</mat-checkbox>
  <mat-checkbox formControlName="checkbox2">Second Checkbox</mat-checkbox>
  <mat-checkbox formControlName="checkbox3">Third Checkbox</mat-checkbox>
</form>

TypeScript

form: FormGroup;

constructor(private formBuilder: FormBuilder){}

ngOnInit(){

  this.form = this.formBuilder.group({
    checkbox1: [''],
    checkbox2: [''],
    checkbox3: [''],
  });

  this.form.setErrors({required: true});
  this.form.valueChanges.subscribe((newValue) => {
    if (newValue.checkbox1 === true || newValue.checkbox2 === true || newValue.checkbox3 === true) {
      this.form.setErrors(null);
    } else {
      this.form.setErrors({required: true});
    }
  });
}

基本的に、フォームの変更を購読し、新しいフォームの値に応じて必要に応じてエラーを修正します。

2
eper

チェックボックスに(ngModelChange)= "onChange(officeLIST)"を追加し、.tsファイルに以下のコードを追加します。

onChange(items) {
    var found = items.find(function (x) { return x.checked === true; });
    if (found)
      this.isChecked = true;
    else
      this.isChecked = false;
  }

必要な場所にisChecked変数を使用します。

0
shailesh kumar