Angular 5,Angular Material Checkbox,有3种状态(选中,未选中,不确定)

Tom*_*all 8 typescript angular-material angular

我是Angular和Angular Material的新手,现在我在一些项目中担任支持.有一个带过滤器和一个复选框的网格,用于检查网格中的用户是处于活动状态,非活动状态还是未选择状态.只有两个选项(活动,非活动)会更简单,但是,我必须为它制作3个状态:

  1. 第一次点击 - 检查是否有效
  2. 第二次单击 - 未选中为非活动状态
  3. 第3次点击 - 不选择不确定

以下是官方Angular Material文档中的复选框示例:https://stackblitz.com/angular/rxdmnbxmkgk? file = app%2Fcheckbox-configurable- example.html

如何以最简单的方式制作它?

smn*_*brv 10

TL; DR

这是一个使用以下解决方案的现成组件:

import { Component, forwardRef, OnInit } from '@angular/core';
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
import { MAT_CHECKBOX_CLICK_ACTION } from '@angular/material';

@Component({
  selector: 'app-tri-state-checkbox',
  templateUrl: './tri-state-checkbox.component.html',
  providers: [
    {
      provide: NG_VALUE_ACCESSOR,
      useExisting: forwardRef(() => TriStateCheckboxComponent),
      multi: true,
    },
    { provide: MAT_CHECKBOX_CLICK_ACTION, useValue: 'noop' },
  ],
})
export class TriStateCheckboxComponent implements ControlValueAccessor {

  tape = [null, true, false];

  value: boolean;

  disabled: boolean;

  private onChange: (val: boolean) => void;
  private onTouched: () => void;

  writeValue(value: boolean) {
    this.value = value;
  }

  setDisabledState(disabled: boolean) {
    this.disabled = disabled;
  }

  next() {
    this.onChange(this.value = this.tape[(this.tape.indexOf(this.value) + 1) % this.tape.length]);
    this.onTouched();
  }

  registerOnChange(fn: any) {
    this.onChange = fn;
  }

  registerOnTouched(fn: any) {
    this.onTouched = fn;
  }

}
Run Code Online (Sandbox Code Playgroud)

和模板:

<mat-checkbox [ngModel]="value" (click)="next()" [disabled]="disabled" [indeterminate]="value === false" [color]="value === false ? 'warn' : 'accent'">
  <ng-content></ng-content>
</mat-checkbox>
Run Code Online (Sandbox Code Playgroud)

用法:

<app-tri-state-checkbox [(ngModel)]="done">is done</app-tri-state-checkbox>
<app-tri-state-checkbox formControlName="done">is done</app-tri-state-checkbox>
Run Code Online (Sandbox Code Playgroud)

原始答案

解决方案1: stackblitz

第一个解决方案是提供MAT_CHECKBOX_CLICK_ACTIONnoop,并有所有点击事件的乐趣,但它是不是很舒服,因为你可以在同一页上多个复选框,而不是所有的人都是三态复选框.

零件:

import { MAT_CHECKBOX_CLICK_ACTION } from '@angular/material';

@Component({
  selector: 'material-app',
  templateUrl: 'app.component.html',
  providers: [
    // provide on THIS component level only
    { provide: MAT_CHECKBOX_CLICK_ACTION, useValue: 'noop' }
  ],
})
export class AppComponent {
  tape = [null, true, false];

  done = null;

  doneControl = new FormControl(false);
}
Run Code Online (Sandbox Code Playgroud)

磁带(一系列切换值)值是:

  • null 为空复选框
  • true 完成
  • false 因为不会这样做

然后在模板文件中使用它:

<mat-checkbox [ngModel]="done" 
              [indeterminate]="done === false" 
              (click)="done = tape[(tape.indexOf(done) + 1) % tape.length]"
              [color]="done === false ? 'warn' : 'accent'">
    Tri-state mat-checkbox with ngModel
</mat-checkbox>

<br>

<mat-checkbox [formControl]="doneControl" 
              [indeterminate]="doneControl.value === false" 
              (click)="doneControl.setValue(tape[(tape.indexOf(doneControl.value) + 1) % tape.length])"
              [color]="doneControl.value === false ? 'warn' : 'accent'">
    Tri-state mat-checkbox with formControl
</mat-checkbox>
Run Code Online (Sandbox Code Playgroud)

解决方案2: stackblitz

我遇到的另一个解决方案是更改ngModelChange处理程序以对模型的先前值做出反应.但这适用ngModelformControl/不适用formControlName.与第一个解决方案相比有什么变化:

  • 没有MAT_CHECKBOX_CLICK_ACTION被覆盖
  • click事件更改为 ngModelChange

零件:

@Component({
  selector: 'material-app',
  templateUrl: 'app.component.html'
})
export class AppComponent {
  tape = [null, true, false];

  done = null;

  doneControl = new FormControl(false);
}
Run Code Online (Sandbox Code Playgroud)

模板:

<mat-checkbox [ngModel]="done" 
              [indeterminate]="done === false" 
              (ngModelChange)="done = tape[(tape.indexOf(done) + 1) % tape.length]"
              [color]="done === false ? 'warn' : 'accent'">
    Tri-state mat-checkbox with ngModel
</mat-checkbox>

<br>

<mat-checkbox [formControl]="doneControl" 
              [indeterminate]="doneControl.value === false" 
              (ngModelChange)="doneControl.setValue(tape[(tape.indexOf(doneControl.value) + 1) % tape.length])"
              [color]="doneControl.value === false ? 'warn' : 'accent'">
    Tri-state mat-checkbox with formControl
</mat-checkbox>
Run Code Online (Sandbox Code Playgroud)

这里模型使用单向绑定设置,不确定模式严格地绑定到false值,颜色也根据值更改.

  • 对于以前使用材质 8 的“noop”并以此为例转向材质 9 的任何人,两者之间的一个重要区别是默认选项的颜色设置为“accent”。如果您现在指定自己的默认选项而不仅仅是单击操作,它将消除强调色。我花了几个小时试图找出复选框不起作用的原因。事实证明确实如此,只是没有显示强调色。如果要保留原始行为,请使用 { Provide: MAT_CHECKBOX_DEFAULT_OPTIONS, useValue: { clickAction: 'noop', color: 'accent' } } (5认同)
  • 我注意到从不确定过渡到检查时动画中有一些闪烁。将值分配给 mat-checkbox 的 checked 属性而不是 ngModel 绑定似乎可以解决问题。模板: &lt;mat-checkbox [checked]="value" ... &gt; &lt;ng-content&gt;&lt;/ng-content&gt; &lt;/mat-checkbox&gt; (3认同)
  • 在 Angular Material 版本 9 中:重大更改:MAT_CHECKBOX_CLICK_ACTION 已弃用,请使用 MAT_CHECKBOX_DEFAULT_OPTIONS。请参阅:https://github.com/angular/components/releases/tag/9.0.0-next.2 (2认同)