【发布时间】:2018-01-16 09:27:19
【问题描述】:
如何从mat-selection-list 中选择单个复选框。类似于从一组值中接受一个值的单选按钮。
【问题讨论】:
如何从mat-selection-list 中选择单个复选框。类似于从一组值中接受一个值的单选按钮。
【问题讨论】:
组件 >= 9.1.0
选择列表现在直接支持单一选择模式。通过将多个输入设置为 false 来启用它。
<mat-selection-list [multiple]="false">...
组件
您必须在初始化时为组件引用的 selectedOptions 属性设置 SelectionModel。
@ViewChild(MatSelectionList, {static: true})
private selectionList: MatSelectionList;
ngOnInit() {
this.selectionList.selectedOptions = new SelectionModel<MatListOption>(false);
}
这样你也可以定义最初选择的值。
export declare class SelectionModel<T> {
constructor(_multiple?: boolean, initiallySelectedValues?: T[], _emitChanges?: boolean);
}
【讨论】:
如果您对每个 mat-checkbox 使用 ngFor,您可以在 HTML 模板中执行类似以下操作:
<ng-container *ngFor="let address of person.addresses; let i = index">
<mat-checkbox [checked]="personCheckedIndex === i" (change)="customerCheckboxChange($event, i)"></mat-checkbox>
</ng-container>
在 TS 中:
public personCheckedIndex = -1;
// Called from template when checkbox value changes
personCheckboxChange(event: MatCheckboxChange, index: number) {
// This allows only one checkbox to be checked among each checkbox
this.personCheckedIndex = event.checked ? index : -1;
}
【讨论】:
聚会晚了,但这是我想出的一个解决方案,它使用指令来扩展 mat-selection-list 行为。
import { SelectionModel } from "@angular/cdk/collections";
import { Directive, Host, Input, OnChanges } from "@angular/core";
import { MatListOption, MatSelectionList } from "@angular/material/list";
@Directive({
selector: "mat-selection-list[multiple]"
})
export class MatSelectionListMultipleDirective implements OnChanges {
private matSelectionList: MatSelectionList;
@Input()
public multiple: boolean;
constructor(@Host() matSelectionList: MatSelectionList) {
this.matSelectionList = matSelectionList;
}
public ngOnChanges(): void {
if (this.multiple) {
this.matSelectionList.selectedOptions = new SelectionModel<MatListOption>(true, this.matSelectionList.selectedOptions.selected);
}
else {
let selected = this.matSelectionList.selectedOptions.selected.splice(0, 1);
this.matSelectionList.selectedOptions = new SelectionModel<MatListOption>(false, selected);
}
}
}
你可以这样使用...
<mat-selection-list [multiple]="false">
...
</mat-selection-list>
理想情况下,我们应该有一个无线电控件而不是复选框,但我认为这个解决方法是可以的,直到 angular material 团队正式支持它。
【讨论】:
你需要做的是:
selectionChange deselectAll()方法清除所有我从 API 页面修改了原始示例,为选择列表添加了一个 ViewChild 并订阅了selectionChange 事件。
ngOnInit(){
this.shoes.selectionChange.subscribe((s: MatSelectionListChange) => {
this.shoes.deselectAll();
s.option.selected = true;
});
// WARNING: Don't attempt to do the following to select the value
// it won't trigger the value change event so it will remain unchecked
// this.shoes.selectedOptions.select(s.option);
// If interested source is here :
// https://github.com/angular/material2/blob/fa4ddd0a13461b2f846e114fd09f8f4e21b814b1/src/lib/list/selection-list.ts
}
【讨论】:
首先,mat-selection-list 不适合单值选择,因为它偏离了its intent:
组中的复选框是非排他性选项;在任何给定时间都可以选中一个组中的多个复选框
你正在寻找的是单选按钮元素本身,因为语义上it stands for:
单选按钮是代表互斥选择的一组控件之一
不幸的是,Angular Material 不包含mat-radio-list 组件。但是您仍然可以通过在您的mat-list-item 中包含mat-radio-button 来实现它。这将提供最佳实践,因为它向用户表明视图中的列表旨在用于互斥选择(与表示多项选择的复选框不同)。而且由于单选按钮正在更新单个变量,因此您将获得排他性:
<mat-list role="list">
<mat-list-item role="listitem" *ngFor="let x of [0,1,2]; let i = index">
<mat-radio-button [value]="i" (change)="selection = $event.value">
Item {{x}}
</mat-radio-button>
</mat-list-item>
</mat-list>
【讨论】:
mat-radio-button 在里面工作有点巧合mat-list-item,如果您使用更高级的功能,可能会崩溃。例如,尝试将matListIcon 添加到您的列表中——现在单选按钮被限制在“行容器”内,并且一旦您单击它就会变得疯狂。我想我们需要一个mat-radio-list。
你可以声明mat-list-option的[selected]属性
例如:
<mat-selection-list #list>
<mat-list-option *ngFor="let item of myList"
[(mgModel)]="selectedOption"
[selected]="item.id === selectedOption.id"
[value]="item">
{{item.name}}
</mat-list-option>
</mat-selection-list>
通过这种方式,您只需选择一个而不更改任何 MatSelectionList 隐藏属性。
您也可以通过将ngModel 替换为控制器逻辑来做到这一点,
通过这种方式,您会将最后一个选择对象保存在类变量中。
<mat-list-option (selectionChange)="onChange($event)"`
【讨论】:
从哲学和用户体验的角度来看,您需要使用单选按钮。这是提供用户友好的“预期”行为的唯一方法。
【讨论】:
如果您不使用 Angular Material v6+,为了从 mat-selection-list 中选择单个复选框,这是我使用的解决方法: 假设我们有一个类别复选框列表。
在您的 HTML 中:
<mat-selection-list>
<mat-list-option (selectionChange)="handleSelection($event, category)" *ngFor="let category of categories" [value]="category">
<span >{{category.name}}</span>
</mat-list-option>
</mat-selection-list>
在您的 .TS 中:
handleSelection(event, categorySelected) {
if (event.selected) {
event.source.selectionList.options.toArray().forEach(element => {
if (element.value.name!= categorySelected.name) {
element.selected = false;
}
});
}
}
这里的关键是使用 MatListOption 上的属性 selectionChange 而不是 MatSelectionList。
【讨论】:
mat-selection-list 显示在使用ngIf 显示/隐藏的模式中,因此将列表注册为@ViewComponent 没有任何作用。 mat-angular 团队应该把它作为一个简单的属性。
只需将MatSelectionList的multiple选项设置为false即可:
ngOnInit() {
this.links.selectedOptions._multiple = false;
}
你就完成了。同样通过这样做,您将能够取消选中选中的复选框。
【讨论】:
您需要的可能是<mat-radio-group> 而不是<mat-selection-list>,它是一个选项列表,但只能选择一个选项。可以在Angular Material docs 找到一个示例。
但请注意,您将获得一个单选按钮,而不是一个复选框。
【讨论】:
试试这个:
ts:
import { Component, OnInit, ViewChild} from '@angular/core';
import { MatSelectionList } from '@angular/material';
@Component({
selector : 'app-xxx',
templateUrl: './xxx.component.html'
})
export class xxxComponent implements OnInit {
public data: Object[] = [ {name : "name 1" }, {name : "name 2" }, {name : "name 3" }, {name : "name 4" } ];
@ViewChild('element_id') names_list: MatSelectionList;
ngOnInit() {
// only if the element is visible on the page, otherwise move this block and execute it until the list is displayed
setTimeout(()=>{
this.names_list.selectedOptions._multiple = false;
},0);
}
}
模板:
<mat-selection-list #element_id>
<mat-list-option *ngFor="let d of data">
{{ d.name }}
</mat-list-option>
</mat-selection-list>
【讨论】:
您可以使用 'mat-checkbox' 而不是 'mat-selection-list' 并像这样玩点击事件:
HTML
<div *ngFor=" ... loop">
<mat-checkbox #checkBoxes (click)="changeCheckBox()">
</mat-checkbox>
</div>
TS
@ViewChildren('checkBoxes') checkBoxes: QueryList<MatCheckbox>;
changeCheckBox() {
this.checkBoxes.filter((checkbox: MatCheckbox) =>
checkbox.checked === true
)[0].checked = false;
}
记住所有复选框的默认值都是未选中的。
【讨论】:
从 Angular Material 9.1.0 开始,选择列表支持单选模式。将multiple 输入设置为false 启用它:https://material.angular.io/components/list/api#MatSelectionList
【讨论】:
试试这个: 我已经让它在一个刻度上工作,改变 css
:host ::ng-deep .mat-radio-outer-circle{
border-radius:2px;
}
:host ::ng-deep .mat-radio-inner-circle{
border-radius:2px;
background-color: transparent!important;
border-bottom: 4px solid white;
border-right:4px solid white;
height:30px;
width:15px;
margin-top: -8px;
margin-left: 3px;
}
:host ::ng-deep .mat-radio-checked .mat-radio-outer-circle{
background:#ff4081!important;
}
:host ::ng-deep .mat-radio-checked .mat-radio-inner-circle{
transform: rotate(45deg) scale(0.5);
}
:host ::ng-deep .mat-radio-button .mat-radio-ripple{
height: 20px; /*double of your required circle radius*/
width: 20px; /*double of your required circle radius*/
left: calc(50% - 10px); /*'10px'-same as your required circle radius*/
top: calc(50% - 10px); /*'10px'-same as your required circle radius */
}
【讨论】:
这是一个简单的解决方案,虽然不是完美的解决方案,但它可以完成您的工作!
change() {
if (this.formGroup.get('control1').value === true) {
this.formGroup.get('control2').setValue(false);
} else if (this.formGroup.get('control2').value === true){
this.formGroup.get('control1').setValue(false);
}
}
<mat-checkbox [formControlName]="'control1'" color="primary" (change)="change()">
control1
</mat-checkbox>
<mat-checkbox color="primary" [formControlName]="'control2'" (change)="change()">
control2
</mat-checkbox>
【讨论】: