Set indeterminate on Angular checkbox

时间:2019-01-07 13:06:35

标签: angular checkbox

I'm trying to programatically set the value of Angular checkboxes to either, false true or indeterminate. I understand that I cannot set the checkbox to the value indeterminate however we do have access to [indeterminate] on the input. Is it possible to set all three states via ngModel somehow?

I have the following code which kinda works, however I am getting a ExpressionChangedAfterItHasBeenCheckedError error.

HTML

<div *ngFor="let label of ClientLabels | async">
  <label for="{{label.objectId}}">{{label.labelName}}</label>
  <input id="{{label.objectId}}" type="checkbox" name="group" [indeterminate]="checkedLabels()"
      [checked]="checkedLabels(label)" (change)="toggleSelectedLabels(label)" />
</div>

TS

checkedLabels(label): boolean {
    const index = this.selectedLabels.indexOf(label.objectId);
    this. indeterminateState = false;
    if (!this.selectedClients.length) {
      return false;
    }
    if (this.countInArray(this.selectedLabels, label.objectId) === this.selectedClients.length) {
      return true;
    }
    if (index >= 0) {
      this. indeterminateState = true;
    }
  }

countInArray(array, value) {
  return array.reduce((n, x) => n + (x === value), 0);
}

Here the use case is similar to that of labels in Gmail, except clients are used in the place of an email. If all of the emails have the same label then they show as checked, however if not all of them share the label then it will show an indeterminate which can be cycled through the three states (true, false, indeterminate).

Q1. How can I cycle through these three state in the same way as you can with gmail?

Q2. Why am I getting the ExpressionChangedAfterItHasBeenCheckedError with the current setup?

Here is a Stackblitz of current progress https://stackblitz.com/edit/angular-3bbutx

Example of Gmail Tri-State checkbox

3 个答案:

答案 0 :(得分:2)

要使复选框不确定,可以使用指令

import { Directive, ElementRef,Input } from '@angular/core';

@Directive({ selector: '[indeterminate]' })
export class IndeterminateDirective {
   @Input() 
   set indeterminate(value)
   {
     this.elem.nativeElement.indeterminate=value;
   }
    constructor(private elem: ElementRef) {
    }
}

然后您的复选框就像

<input class="pull-left" type="checkbox" 
     [indeterminate]="client.indeterminated" 
     [checked]="client.checked" (click)="click(client)"/>

其中

  click(cliente: any) {
    let indeterminated=(!cliente.checked && !cliente.indeterminated) ? true : false;
    let checked=(!cliente.checked && cliente.indeterminated)?true:false
    cliente.indeterminated = indeterminated;
    cliente.checked=checked;
  }

看到您有两个变量“ checked”和“ indeterminated”,可以根据需要进行循环

答案 1 :(得分:0)

是的,您可以使用 [indeterminate]="condition"(没有任何指令)。 你不能做indeterminate="{{condition}}"。 不同之处在于 [...] 设置元素的属性,而没有括号则设置属性。 HTMLInput 元素具有属性 indeterminate,但没有这样的属性。

为了使用同时保持 checkedindeterminate 状态的 ngModel 或 FormControl,您应该在主要组件中创建自定义指令或/和其他逻辑(作为参考,请参阅 { {3}} 来自 @Eliseo)。

<块引用>

第一季度。我怎样才能像使用 gmail 一样循环浏览这三种状态?

处理点击,循环更改“已检查”和“不确定”对的状态。 answer

<块引用>

第 2 季度。为什么我在当前设置中收到 ExpressionChangedAfterItHasBeenCheckedError?

您在 checkedLabels 方法中有副作用,每次 Angular 检查表达式 [indeterminate]="checkedLabels()" 的值时,该方法都会更改组件的状态。

答案 2 :(得分:0)

经过长时间的搜索,我是这样做的:

在html文件中:

<input #checkboxes
       type="checkbox"
       [checked]="some_condition"
       [indeterminate]="!some_condition && some_another_condition">
<b class="checkbox-container"></b>

并在 css 文件中:

      input[type=checkbox]:checked + b:before {
           content: "\2713";
           font-family: ux-icons;

      }

  input[type=checkbox]:indeterminate + b:before {
       content: "\f067";
       font: 14px/1 DXIcons;
  }