【问题标题】:Angular mat-selection-list, How to make single checkbox select similar to radio button?Angular mat-selection-list,如何使单个复选框选择类似于单选按钮?
【发布时间】:2018-01-16 09:27:19
【问题描述】:

如何从mat-selection-list 中选择单个复选框。类似于从一组值中接受一个值的单选按钮。

【问题讨论】:

    标签: angular angular-material


    【解决方案1】:

    组件 >= 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);
    }
    

    MatSelectionList api

    这样你也可以定义最初选择的值。

    export declare class SelectionModel<T> {
        constructor(_multiple?: boolean, initiallySelectedValues?: T[], _emitChanges?: boolean);
    }
    

    GitHub api

    【讨论】:

    • 抱歉这个问题。我是角度的新手。如何引用组件中的选择列表?如何获得 this.selectionList?
    • 看看 ViewChild 装饰器:angular.io/api/core/ViewChild。有了它,您可以引用模板中的任何组件或元素。
    • 如何更改复选框列的顺序为先在细节之前?
    • 我不能在 @ViewChildren 中使用与 QueryList 相同的方式。有什么解决办法吗?
    • @SasinduLakshitha 从 9.1.0 版本开始,您不必使用“@ViewChildren”。请参阅编辑后的答案。
    【解决方案2】:

    如果您对每个 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;
    }
    

    【讨论】:

      【解决方案3】:

      聚会晚了,但这是我想出的一个解决方案,它使用指令来扩展 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 团队正式支持它。

      【讨论】:

      • mat-selection-list 中没有像 multiple 这样的输入。
      • 目前没有 - 这个指令添加了输入和行为。
      • 如果您无法升级到最新的 Angular Material,并且可能想在您的 mat-selection-list 上使用 *ngIf,这是最干净的解决方案!
      【解决方案4】:

      你需要做的是:

      • 收听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
      }
      

      工作样本: https://stackblitz.com/edit/angular-i3pfu2-6n5cnt

      另请参阅: https://material.angular.io/components/list/api

      【讨论】:

      • 注意:我报告了 selectionModel.select 不工作的问题,它已经修复了推送 - 所以将来应该可以工作
      • 如果您需要复选框,这是一个很好的解决方案,因为 multiple= flase 会隐藏它们。
      【解决方案5】:

      首先,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>
      

      Check a Stackblitz

      【讨论】:

      • 我同意如果是单选,你应该使用单选按钮而不是复选框——毕竟这是单选样式的重点——但 mat-radio-button 在里面工作有点巧合mat-list-item,如果您使用更高级的功能,可能会崩溃。例如,尝试将matListIcon 添加到您的列表中——现在单选按钮被限制在“行容器”内,并且一旦您单击它就会变得疯狂。我想我们需要一个mat-radio-list
      【解决方案6】:

      你可以声明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)"`
      

      另见Binding an Angular Material Selection List

      【讨论】:

        【解决方案7】:

        从哲学和用户体验的角度来看,您需要使用单选按钮。这是提供用户友好的“预期”行为的唯一方法。

        【讨论】:

          【解决方案8】:

          如果您不使用 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 团队应该把它作为一个简单的属性。
          【解决方案9】:

          只需将MatSelectionList的multiple选项设置为false即可:

          ngOnInit() {
            this.links.selectedOptions._multiple = false;
          }
          

          你就完成了。同样通过这样做,您将能够取消选中选中的复选框。

          【讨论】:

            【解决方案10】:

            您需要的可能是&lt;mat-radio-group&gt; 而不是&lt;mat-selection-list&gt;,它是一个选项列表,但只能选择一个选项。可以在Angular Material docs 找到一个示例。

            但请注意,您将获得一个单选按钮,而不是一个复选框。

            【讨论】:

              【解决方案11】:

              试试这个:

              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>
              

              【讨论】:

                【解决方案12】:

                您可以使用 '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;
                  }
                

                记住所有复选框的默认值都是未选中的。

                【讨论】:

                  【解决方案13】:

                  从 Angular Material 9.1.0 开始,选择列表支持单选模式。将multiple 输入设置为false 启用它:https://material.angular.io/components/list/api#MatSelectionList

                  【讨论】:

                  • Angular 11 [multiple]="false" not working for me得到错误:`错误NG8002:无法绑定到'multiple',因为它不是'mat-selection-的已知属性- list'.`有什么想法吗?
                  【解决方案14】:

                  试试这个: 我已经让它在一个刻度上工作,改变 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 */
                      }
                  

                  【讨论】:

                    【解决方案15】:

                    这是一个简单的解决方案,虽然不是完美的解决方案,但它可以完成您的工作!

                     
                    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>

                    【讨论】:

                      猜你喜欢
                      • 1970-01-01
                      • 1970-01-01
                      • 2014-06-24
                      • 1970-01-01
                      • 1970-01-01
                      • 2020-03-24
                      • 1970-01-01
                      • 1970-01-01
                      • 2015-11-02
                      相关资源
                      最近更新 更多