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

Uncheck active Angular Material toggle buttons on click

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

我尝试了几种方法,例如

模板:

<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;
}

但这并没有更新按钮的 '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>

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

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

我试过:

@ViewChildren('no_btn') no_btn: ElementRef;

然后:

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

但结果似乎与在函数中传递按钮引用没有任何不同;再次单击该按钮不会取消选中它。禁用 确实 有效,所以我认为我的代码是正确的:

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

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

<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

根据源代码 (^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;
    }
 }

这是另一种解决方案。请注意,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>

这是一个基于的简单指令:

@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>