在Angular复选框上设置不确定状态

6
我正在尝试以编程方式将Angular复选框的值设置为falsetrueindeterminate。 我知道我不能将复选框设置为值indeterminate,但是我们可以在输入上访问[indeterminate]。 是否有可能通过ngModel以某种方式设置所有三个状态?
我有以下代码,它有点起作用,但是我得到了一个ExpressionChangedAfterItHasBeenCheckedError错误。
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);
}

这里的用例与Gmail标签相似,不同之处在于客户端被用作邮件。如果所有邮件都有相同的标签,则它们将显示为已选中,但是如果它们没有共享标签,则它将显示为不确定状态,可以通过三种状态(true、false、不确定)循环。

Q1. 如何像Gmail一样循环遍历这三种状态?

Q2. 为什么我会在当前设置下收到ExpressionChangedAfterItHasBeenCheckedError错误?

这是当前进度的Stackblitz https://stackblitz.com/edit/angular-3bbutx

Gmail三态复选框示例


请在您的问题中将“intermediate”更改为“indeterminate”。 - ConnorsFan
感谢 @ConnorsFan。 - Taylorsuk
3个回答

12
使复选框变为不确定状态,您可以使用指令。

要使复选框变为不确定状态,您可以使用指令。

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"(未确定的),你可以按照自己的意愿进行循环。


我们能轻松地将 false 添加到其中吗?这样它就可以在三个之间循环了吗? - Taylorsuk
https://stackblitz.com/edit/angular-3wacqt?file=src%2Fapp%2Fhello.component.ts。如果您单击“使循环运行:不确定-检查-取消选中”。注意:当“indeterminated”为真时,无需导入是否已选中。 - Eliseo
3
@Eliseo,<input type="checkbox"> 已经有了 indeterminate 属性,所以如果你删除这个指令,它仍然可以正常工作。 - Diego Ortiz
@DiegoOrtiz,你能否创建一个 StackBlitz 吗?没有指令我无法想象如何制作。 - Eliseo

4

是的,你可以使用[indeterminate]="condition"(不带任何指令)。 你不能使用indeterminate="{{condition}}"。 区别在于[...]设置元素的属性,而没有方括号则设置属性。HTMLInput元素具有属性indeterminate,但不具备这种属性。

为了使用ngModel或FormControl,同时持有checkedindeterminate状态,你应该创建一个自定义指令或/和在主要组件中添加额外的逻辑(请参考@Eliseo的答案)。

Q1. 我如何像gmail那样循环遍历这三个状态?

处理单击事件,循环更改“checked”和“indeterminate”对的状态。可参考此示例(使用jQuery)

Q2. 为什么我当前的设置会导致ExpressionChangedAfterItHasBeenCheckedError错误?

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


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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接