Angular 5,具有 3 种状态的 Angular 材质复选框(选中、未选中、不确定)
Posted
技术标签:
【中文标题】Angular 5,具有 3 种状态的 Angular 材质复选框(选中、未选中、不确定)【英文标题】:Angular 5, Angular Material Checkbox with 3 states (checked, unchecked, indeterminate) 【发布时间】:2018-08-24 01:31:08 【问题描述】:我是 Angular 和 Angular Material 的新手,现在我在某个项目中担任支持人员。有一个带有过滤器的网格和一个复选框,用于检查网格中的用户是否处于活动状态、非活动状态或未被选中。只有两个选项(活动、非活动)会更简单,但是我必须为其设置 3 个状态:
-
第一次点击 - 检查是否有效
第二次点击 - 未选中为非活动状态
第三次点击 - 未选择的不确定
这是来自官方 Angular Material 文档的复选框示例: https://stackblitz.com/angular/rxdmnbxmkgk?file=app%2Fcheckbox-configurable-example.html
如何用最简单的方式制作?
【问题讨论】:
在最坏的情况下,双复选框,一个用于选择/未选择,一个用于活动/非活动。三状态复选框可能是可行的,但会违反用户对经典复选框的期望,因此可能会影响用户体验。 【参考方案1】:@angular/material >= 9
这是一个现成的组件:
import Component, forwardRef, Input from '@angular/core';
import ControlValueAccessor, NG_VALUE_ACCESSOR from '@angular/forms';
import MatCheckboxDefaultOptions, MAT_CHECKBOX_DEFAULT_OPTIONS from '@angular/material/checkbox';
@Component(
selector: 'app-tri-state-checkbox',
templateUrl: './tri-state-checkbox.component.html',
styleUrls: ['./tri-state-checkbox.component.scss'],
providers: [
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => TriStateCheckboxComponent),
multi: true,
,
provide: MAT_CHECKBOX_DEFAULT_OPTIONS, useValue: clickAction: 'noop' as MatCheckboxDefaultOptions ,
],
)
export class TriStateCheckboxComponent implements ControlValueAccessor
@Input() tape = [null, true, false];
value: any;
disabled: boolean;
private onChange: (val: boolean) => void;
private onTouched: () => void;
writeValue(value: any)
this.value = value || this.tape[0];
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;
和模板:
<mat-checkbox [ngModel]="value" (click)="next()" [disabled]="disabled" [indeterminate]="value === false" [color]="value === false ? 'warn' : 'accent'">
<ng-content></ng-content>
</mat-checkbox>
用法:
<app-tri-state-checkbox [(ngModel)]="done">is done</app-tri-state-checkbox>
<app-tri-state-checkbox formControlName="done">is done</app-tri-state-checkbox>
您还可以将默认磁带覆盖为例如枚举值:
<app-tri-state-checkbox [tape]="customTape" [(ngModel)]="done">is done</app-tri-state-checkbox>
其中customTape
替换默认值[null, true, false]
customTape = [Status.open, Status.complete, Status.cancelled];
@angular/material
改变一下
provide: MAT_CHECKBOX_DEFAULT_OPTIONS, useValue: clickAction: 'noop' as MatCheckboxDefaultOptions ,
自第 9 版以来已弃用的 MAT_CHECKBOX_CLICK_ACTION
provide: MAT_CHECKBOX_CLICK_ACTION, useValue: 'noop' ,
【讨论】:
在 Angular 材料的第 9 版中:重大更改:不推荐使用 MAT_CHECKBOX_CLICK_ACTION,请使用 MAT_CHECKBOX_DEFAULT_OPTIONS。见:github.com/angular/components/releases/tag/9.0.0-next.2 对于以前使用材料 8 的“noop”并以此为例移动到材料 9 的任何人,两者之间的一个重要区别是默认选项将颜色设置为“强调”。如果您现在指定自己的默认选项而不是仅单击操作,它将消除强调色。我花了几个小时试图弄清楚为什么复选框不起作用。事实证明,它只是没有显示强调色。如果要保留原始行为,请使用 provide: MAT_CHECKBOX_DEFAULT_OPTIONS, useValue: clickAction: 'noop', color: 'accent' 我注意到在从不确定转换时动画中出现了一些闪烁 -> 检查。将值分配给 mat-checkbox 的 checked 属性而不是 ngModel 绑定似乎可以解决问题。模板:[disabled]
作为输入也可能适用于模板驱动的表单,但不适用于反应式表单【参考方案2】:
我试图回复这个Answer,但我没有足够的声誉。首先感谢您的回答和深入的解释。我在复选框的版本上遇到了问题,我发现如果此行的值为 false
this.value = value || this.tape[0];
不起作用,颜色也没有更新。我为这个改了
this.value = value !== null ? value : this.tape[0];
我希望此评论对其他人有所帮助。
【讨论】:
谢谢 - 这解决了我的问题,赞成给你更多的代表【参考方案3】:我想要一个解决方案,而不需要另一个组件并且采用反应形式,这似乎确实可以解决问题,尽管在一个过渡中存在重复的动画:
component.ts
onChangeCheckbox(checkbox: MatCheckbox): void
if (checkbox.indeterminate)
checkbox.indeterminate = false;
checkbox.checked = true;
// by the time you click it is changed
else if (!checkbox.indeterminate && !checkbox.checked )
checkbox.checked = false;
else if (!checkbox.indeterminate && checkbox.checked )
checkbox.indeterminate = true;
component.html
<mat-checkbox
#checkboxName
formControlName="checkboxName"
indeterminate="true"
(change)="onChangeCheckbox(checkboxName)"
id="edit:checkboxName">
Checkbox Name
</mat-checkbox>
【讨论】:
将 MatCheckbox 传递给函数的想法是我所需要的。就我而言,我不复制任何东西。谢谢! :)【参考方案4】:执行此操作的一种方法是将 MAT_CHECKBOX_CLICK_ACTION 设置为“noop”,然后您必须使用(单击)设置选中的值。不要忘记绑定 [ngModel] 和 [indeterminate]。
providers: [
provide: MAT_CHECKBOX_CLICK_ACTION, useValue: 'noop'
]
看看这个:https://github.com/angular/material2/blob/master/src/lib/checkbox/checkbox.md
【讨论】:
【参考方案5】:如果您需要一个工作示例,您还可以克隆 material2 项目here,然后:
cd material2
npm i
npm run demo-app
打开演示应用并导航到复选框组件。
【讨论】:
【参考方案6】:感谢您的解决方案!在这里使用 Angular 9.1.7。
我需要一组自定义值。这不是开箱即用的。感谢这个 (post) 启发我创建 2-way binding 的解决方案
我将部分更改如下:
模板:
<mat-checkbox (click)="next()"
[(ngModel)]="guiValue"
[disabled]="disabled"
[indeterminate]="isIndeterminate"
[color]="isIndeterminate ? 'warn' : 'accent'"
><ng-content></ng-content>
</mat-checkbox>
打字稿:
import Component, EventEmitter, forwardRef, Input, Output from '@angular/core';
import ControlValueAccessor, NG_VALUE_ACCESSOR from '@angular/forms';
import MatCheckboxDefaultOptions, MAT_CHECKBOX_DEFAULT_OPTIONS from '@angular/material/checkbox';
@Component(
selector: 'app-tri-state-checkbox',
templateUrl: './tri-state-checkbox.component.html',
styleUrls: ['./tri-state-checkbox.component.css'],
providers: [
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => TriStateCheckboxComponent),
multi: true,
,
provide: MAT_CHECKBOX_DEFAULT_OPTIONS, useValue: clickAction: 'noop' as MatCheckboxDefaultOptions ,
],
)
export class TriStateCheckboxComponent implements ControlValueAccessor
internalValue: any;
guiValue: any;
disabled: boolean;
isIndeterminate: boolean;
@Input() states = [null, true, false];
@Output() triStateValueChange = new EventEmitter<any>();
@Input()
get triStateValue(): any
return this.internalValue;
set triStateValue(v)
this.internalValue = v;
this.writeValue();
onChange = (x: any) => console.log(`onChange:$x`); ;
onTouched = () => ;
writeValue()
if (this.internalValue === this.states[0]) this.guiValue = true; // undetermined
else if (this.internalValue === this.states[1]) this.guiValue = true; // true
else if (this.internalValue === this.states[2]) this.guiValue = false; // false
else console.error (`Wrong value for tri state checkbox : $this.internalValue`);
this.isIndeterminate = ( this.internalValue === this.states[0] );
setDisabledState(disabled: boolean)
this.disabled = disabled;
next()
this.determineNextValue();
this.onTouched();
this.onChange(this.guiValue);
determineNextValue()
if (this.internalValue === this.states[0]) this.internalValue = this.states[1];
else if (this.internalValue === this.states[1]) this.internalValue = this.states[2];
else if (this.internalValue === this.states[2]) this.internalValue = this.states[0];
this.triStateValueChange.emit(this.internalValue);
registerOnChange(fn: any)
this.onChange = fn;
registerOnTouched(fn: any)
this.onTouched = fn;
及用法:
模板:
<app-tri-state-checkbox [states]="locTriState" [(triStateValue)]="targetVariable" ">Labeltext</app-tri-state-checkbox>
并使用组件设置源 (TS):(变量 targetVariable
用作使用 2 路绑定的源/目标。
export enum TriStateValues
on,
off,
dontcare
;
let targetVariable = TriStateValues.on;
const locTriState = [ TriStateValues.dontcare, TriStateValues.on , TriStateValues.off];
【讨论】:
【参考方案7】:@angular/材质 >= 9
在我的场景中,它有效。必须提供color: 'primary'
。
providers: [ provide: MAT_CHECKBOX_DEFAULT_OPTIONS, useValue: clickAction: 'noop', color: 'primary' as MatCheckboxDefaultOptions ]
【讨论】:
以上是关于Angular 5,具有 3 种状态的 Angular 材质复选框(选中、未选中、不确定)的主要内容,如果未能解决你的问题,请参考以下文章
如何在 Angular 5 中从 Typescript 调用 JavaScript 函数?
在Angular中->如何使用基于角色的访问权限检查用户是不是具有权限,并将角色保存在数据库中