首页 > 解决方案 > 如何从函数中以编程方式调用 mat-options?

问题描述

我需要在 mat-select 组件上实现对双击事件的处理。这个想法是能够在双击事件上调用函数,但在单击事件上保持正常行为。通常这是不可能的,因为 mat-select 立即显示 mat-options 不允许检测到双击事件。

如果我尝试使用 setTimeOut 添加一些延迟,例如在触发 mat-select 时,mat-options 弹出窗口会立即显示。我找到了一种解决方法,因此我可以通过从一开始使用 [disabled] 禁用 mat-select 来双击 mat-select,这样我可以在不显示 mat-options 的情况下检测到 mat-select 的双击,但是当我尝试启用 mat 时- 从我的 singleClick() 函数中再次选择并再次显示 mat-options 弹出窗口。我不能,因为在我再次单击组件之前,angular 不会呈现新的更改。

理想情况下,我想在我的 mat-select 上单击一下,调用我的 singleClick() 函数,然后使用 [disabled]="false" 再次启用我的 mat-select,最后一次渲染组件,但角度检测只有更改,并且仅在下一次单击交互时才呈现组件。

我想做的是通过调用我的 singleClick() 函数来显示垫选项。有什么方法可以从我的 singleClick 函数中以编程方式调用 mat-options 吗?我希望你能给我一些建议,或者在这种情况下处理双击事件的更好方法。代码示例

这是我的组件:

<mat-select placeholder="Double click posible, single click not showing options until second time clicked" [disabled]="disableMatSelect"
    (click)="singleClick($event)" (dblclick)="doubleClick()" (openedChange)="openedChange($event)" [(value)]="selected">
    <mat-option *ngFor="let option of options" [value]="option.value">
        {{ option.viewValue }}
    </mat-option>
</mat-select>

这是我要调用 mat-options 弹出窗口的函数:

singleClick(event) {
    this.isSingleClick = true;
    setTimeout(() => {
      if (this.isSingleClick && event.type == 'click') {
        this.disableMatSelect = false;

        //Here I would like to call for mat-options popup

        this.clickEvent = 'Single Click';
        
      }
    }, 250);
  }

标签: angulartriggersevent-handlingmouselistenereventtrigger

解决方案


我首先尝试过preventDefault(),但这没有用。所以我想出了这个解决方法,不是最好的,但它可能会为你指明正确的方向。

  1. 我创建了一个不可见的覆盖层来收听点击,然后我stopPropagation()就这样点击永远不会到垫选择。

  2. 我听一下点击,如果里面setTimeout()我们没有第二次点击,然后用.open()方法打开mat,这个可以通过“查看孩子”找到,@ViewChild('matSelect') matSelect: MatSelect;然后this.matSelect.open()

  3. 如果我们再次单击,则转到该doubleClick()方法。

在那里你的stackblitz,你会找到答案和我必须做的改变。

您可以优化覆盖以更好地适应垫选择的大小。

结果

{{clickEvent}}

<div class="select-container">
    <mat-form-field>
        <mat-select #matSelect placeholder=" Normal behavior on single click" (openedChange)=" openedChange($event)">
            <mat-option *ngFor="let option of options" [value]="option.value">
                {{ option.viewValue }}
            </mat-option>
        </mat-select>
    </mat-form-field>
    <div class="click_listener-container" (click)="singleClick($event);">
    </div>
</div>
enum values {
  OPTION_1,
  OPTION_2,
  OPTION_3
}

@Component({
  selector: 'select-overview-example',
  templateUrl: 'select-overview-example.html',
  styleUrls: ['select-overview-example.css']
})
export class SelectOverviewExample {
  @ViewChild('matSelect') matSelect: MatSelect;

  options = [
    { value: values.OPTION_1, viewValue: 'Option 1' },
    { value: values.OPTION_2, viewValue: 'Option 2' },
    { value: values.OPTION_3, viewValue: 'Option 3' }
  ];

  disableMatSelect = true;
  isSingleClick = false;
  clickEvent = 'Not Clicked';

  constructor() {}

  async singleClick(event) {
    event.stopPropagation();

    if (this.isSingleClick) {
      this.doubleClick();
    } else {
      this.isSingleClick = true;

      setTimeout(() => {
        if (this.isSingleClick && event.type == 'click') {
          console.log('single click');
          this.clickEvent = 'Single Click';

          this.isSingleClick = false;
          this.matSelect.open();
        }
      }, 250);
    }
  }

  doubleClick() {
    this.isSingleClick = false;
    this.clickEvent = 'Double Click';
    console.log('======>Doble click');
  }

  openedChange(opened: boolean) {
    if (opened === false) {
      this.disableMatSelect = true;
      console.log('disableMatSelect==', this.disableMatSelect);
    }
  }
}

编辑

如果您有多个垫子选择,您可以使用@ViewChildren如下

@ViewChildren('matSelect')
  matSelections: QueryList<MatSelect>

然后,您可以像跟随一样循环遍历元素。

this.matSelections.toArray().map(async (matSelect) => {
  console.log(matSelect)
}),

推荐阅读