取消选中单击时活动的 Angular Material 切换按钮

Posted

技术标签:

【中文标题】取消选中单击时活动的 Angular Material 切换按钮【英文标题】:Uncheck active Angular Material toggle buttons on click 【发布时间】:2018-12-19 07:06:19 【问题描述】:

我需要修改标准Angular Material toggle button component 的功能,以便单击活动按钮将组件返回到没有按钮处于活动状态的状态。这有两个步骤:

更新切换组的值 将单击按钮的“checked”参数更改为 false

我尝试了几种方法,例如

模板:

<mat-button-toggle-group #group="matButtonToggleGroup">
    <mat-button-toggle #no_btn value="no" (click)="update_toggle(group,no_btn)">No</mat-button-toggle>
    <mat-button-toggle #yes_btn value="yes" (click)="update_toggle(group,yes_btn)">Yes</mat-button-toggle>
</mat-button-toggle-group>

JS:

update_toggle(group,button)
    if(group.value=="")
        group.value = button.value;
    
    else
    
        group.value = "";
    
button.checked=!button.checked;

但这不会更新按钮的“已检查”值,我猜是因为 update_toggle() 设置的组值与单击按钮的用户操作相冲突。

唯一有效的方法是:

<mat-button-toggle-group #group="matButtonToggleGroup">
    <mat-button-toggle #no_btn value="no" (click)="update_toggle(group,no_btn)" (click)="group.value=='no' ? checked=false : checked=false">No</mat-button-toggle>
    <mat-button-toggle #yes_btn value="yes" (click)="update_toggle(group,yes_btn)" (click)="group.value=='yes' ? checked=false : checked=false">Yes</mat-button-toggle>
</mat-button-toggle-group>

但是单个按钮上的两次点击事件感觉非常糟糕,尤其是第二次点击中的三元与本能应该是相反的。

对更好的方法有什么建议吗?

我试过了:

@ViewChildren('no_btn') no_btn: ElementRef;

然后:

this.no_btn['_results'][k]['_inputElement']['nativeElement']['checked']=false;

但是结果似乎和在函数中传递按钮引用没有什么不同;第二次单击该按钮不会取消选中它。禁用 确实 工作,所以我认为我的代码是正确的:

this.no_btn['_results'][k]['_inputElement']['nativeElement']['disabled']=true;

【问题讨论】:

为什么不使用@ViewChild()'s 来获取复选框的实例并以这种方式进行更改? 已经尝试过 - 将更新问题。 这不会改变按钮本身的值,而不是它是否被选中?还是您指的是组的价值,而不是单个按钮? 【参考方案1】:

一个简单的通用解决方案是在多个模式下使用按钮切换并通过组更改事件。 change 事件为您提供所需的一切,因此无需直接访问子组件:

<mat-button-toggle-group multiple (change)="toggleChange($event)">
    <mat-button-toggle value="no">No</mat-button-toggle>
    <mat-button-toggle value="yes">Yes</mat-button-toggle>
</mat-button-toggle-group>

toggleChange(event) 
    let toggle = event.source;
    if (toggle) 
        let group = toggle.buttonToggleGroup;
        if (event.value.some(item => item == toggle.value)) 
            group.value = [toggle.value];
        
    

这里是Stackblitz。

【讨论】:

很好的解决方案 - 谢谢@gtranter。如果有人发现这不起作用,您可能需要更新 Angular Material,在我的情况下,从 5.2.2 更新到 6.4.1。 如果你想在没有 $event.source 的函数中取消选中所有这些怎么办? 该示例支持在没有事件源时取消选中所有选项。【参考方案2】:

这是另一种解决方案。请注意,change 事件发生在 click 事件之前。

组件

toggleChanged: boolean;

onChange() 
  this.toggleChanged = true;


onClick(group: MatButtonToggleGroup) 
  if (!this.toggleChanged) group.value = null;
  this.toggleChanged = false;

模板

<mat-button-toggle-group [(value)]="myValue" #group="matButtonToggleGroup"
    (change)="onChange()" (click)="onClick(group)">
    <mat-button-toggle *ngFor="let item of items" [value]="item.value">
         item.name 
    </mat-button-toggle>
</mat-button-toggle-group>

【讨论】:

change 事件是否总是发生在click 事件之前,或者是因为 Angular 实现而发生的?无论如何,根据我的测试,您的解决方案运行良好!【参考方案3】:

根据源代码 (^6.4.1),change 事件(MatButtonToggle)总是在鼠标点击时触发:

https://github.com/angular/material2/blob/6.4.7/src/lib/button-toggle/button-toggle.ts#L461

我们可以订阅所有切换按钮(或只订阅那些我们想要取消选中的按钮):

<mat-button-toggle-group #group="matButtonToggleGroup">
    <mat-button-toggle value="no" (change)="onChange($event, group)">No</mat-button-toggle>
    <mat-button-toggle value="yes" (change)="onChange($event, group)">Yes</mat-button-toggle>
</mat-button-toggle-group>

我们可以为这些事件添加一个简单的处理程序和一个存储状态的字段:

private _activeValue = "";

onChange(event, group) 
  if (this._activeValue === event.value) 
    // make unchecked
    group.value = "";
    this._activeValue = "";
   else 
    this._activeValue = event.value;
  

This example is on Stackblitz

另一种实现方式:

我们可以绑定value

<mat-button-toggle-group [value]="_activeValue">
    <mat-button-toggle value="no" (change)="onChange($event)">No</mat-button-toggle>
    <mat-button-toggle value="yes" (change)="onChange($event)">Yes</mat-button-toggle>
</mat-button-toggle-group>

public _activeValue = "";
onChange(event, group) 
   if (this._activeValue === event.value) 
       // make unchecked
       this._activeValue = "";
     else 
       this._activeValue = event.value;
    
 

【讨论】:

【参考方案4】:

这是一个基于@Scott VandenToorn's answer的简单指令:

@Directive(
  selector: 'mat-button-toggle-group[appClickOnSelectedButton]',
)
export class ClickOnSelectedButtonDirective 
  @Output() appClickOnSelectedButton = new EventEmitter<PointerEvent>();

  private toggleChanged: boolean = false;

  @HostListener('change', ['$event'])
  onChange(): void 
    this.toggleChanged = true;
  

  @HostListener('click', ['$event'])
  onClick(event: PointerEvent): void 
    if (!this.toggleChanged) 
      const target = event.target as htmlElement;
      const hasClass = hasAncestorTheClass(target, 'mat-button-toggle-checked');
      if (hasClass) 
        this.appClickOnSelectedButton.emit(event);
      
    
    this.toggleChanged = false;
  

hasAncestorTheClass 基于this SO,以防用户在两个选项之间点击。

用法:

<mat-button-toggle-group
  [value]="form.value"
  (appClickOnSelectedButton)="onChange(null)"
  (change)="onChange($event.value)"
>
  <mat-button-toggle [value]="false">No</mat-button-toggle>
  <mat-button-toggle [value]="true">Yes</mat-button-toggle>
</mat-button-toggle-group>

【讨论】:

以上是关于取消选中单击时活动的 Angular Material 切换按钮的主要内容,如果未能解决你的问题,请参考以下文章

单击时如何取消选中复选框

防止复选框在单击时取消选中(不禁用或只读)

如何在单击 ListView 中的按钮时取消选中所有列表项

第二次单击时取消选中单选按钮

单击模态对话框按钮后如何取消选中该复选框?

为啥在单击“全选”按钮后,复选框会被选中,然后又被取消选中?