如何验证是否应选择至少一个复选框?

时间:2017-04-13 06:16:32

标签: forms angular validation typescript

我想在没有表单标签的情况下对复选框进行验证。 至少应选择一个复选框。

<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>

对于其他字段我将把所需要的并执行错误|触摸|有效等但由于复选框不是单输入,我不能在每个复选框中放置所需,因为所有复选框都必须被选中。那么如何进行验证以提醒用户至少应检查一个?

6 个答案:

答案 0 :(得分:19)

考虑创建一个包含您的复选框组的FormGroup,并将组的已检查值绑定到带有必需验证程序的隐藏表单控件。

假设您有三个复选框

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中显示此隐藏控件。

Step3:创建最终表单组包含下面的复选框组和隐藏的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>

参考此demo

答案 1 :(得分:13)

使用reactive forms的最佳,最简单且可能正确的方法是使用一个FormGroup来保存分组的复选框,并创建一个验证器以检查其中是否至少选中了一个(或多个)复选框。组。

要这样做,只需在现有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上一样检查复选框组是否有效:

<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

我创建了一个工作示例,您可以使用它:https://stackblitz.com/edit/angular-at-least-one-checkbox-checked

答案 2 :(得分:2)

在验证(例如某些点击事件)上迭代您的数组并检查至少有一个项是否为真。

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 :(得分:2)

我遇到了同样的问题,这是我最终与Angular 6 FormGroup一起使用的解决方案,因为我没有几个复选框。

HTML 注意:我正在使用Angular Material进行样式设置,请根据需要进行更改。

<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});
    }
  });
}

基本上,订阅表单中的所有更改,然后根据新的表单值根据需要修改错误。

答案 4 :(得分:0)

将(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变量。

答案 5 :(得分:-1)

您应该检查表单元素的触及和脏条件

int get_position()
{
    CFArrayRef a = CGWindowListCopyWindowInfo(kCGWindowListOptionOnScreenOnly, kCGNullWindowID);
    NSArray * arr = CFBridgingRelease(a);
    pid_t window_pid = 0;
    unsigned long count = [ arr count];
    NSMutableDictionary* entry;

    for ( unsigned long i = 0; i < count; i++)
    {
        //CFTypeRef position;
        AXValueRef temp;
        CGPoint current_point;
        entry = arr[i];
        window_pid = [[entry objectForKey:(id)kCGWindowOwnerPID] intValue];
        NSString * temp_ns_string = [entry objectForKey:(id)kCGWindowName ];
        const char *window_name =[temp_ns_string UTF8String];
        printf("%s - ", window_name);
        printf("Pid: %i\n", window_pid);

        AXUIElementRef window_ref = AXUIElementCreateApplication(window_pid);
        AXError error = AXUIElementCopyAttributeValue(window_ref, kAXPositionAttribute, (CFTypeRef *)&temp);

        if ((AXValueGetValue(temp, kAXValueCGPointType, &current_point) ))
        {
            printf("%s - ", window_name);
            printf("Pid: %i - ", window_pid);
            printf(" %f,%f\n", current_point.x, current_point.y);
        }
        else
        {
            printf("%s - ", window_name);
            printf("Pid: %i\n", window_pid);
        }

    }
    return 0;
}

您可以将两个场景的前一个和我的答案结合起来