You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何为mat-select创建自定义指令监听change事件并解决事件捕获失败问题

问题原因
  • Angular Material 的 mat-select 是封装后的自定义组件,不会触发原生DOM的change事件,而是对外抛出自定义的 selectionChange 事件,因此你通过@HostListener('change')监听原生事件的方式无法捕获到mat-select的值变更。
  • 另外mat-select对应的DOM元素不是原生输入框,直接取elementRef.nativeElement.value也无法拿到正确的选中值。
解决方案

修改自定义指令,兼容原生输入框和mat-select两种场景,通过可选注入MatSelect实例的方式监听对应事件:

import { Directive, HostListener, Input, Optional, OnInit, OnDestroy, ElementRef } from '@angular/core';
import { MatSelect } from '@angular/material/select';
import { Subject, takeUntil } from 'rxjs';

// 保留你的原有其他导入
@Directive({
  selector: '[appDeliveryAcross]'
})
export class DeliveryAcrossDirective implements OnInit, OnDestroy {
  @Input('key') key: string = '';
  @Input('component') component: string = '';
  // 用于销毁订阅,避免内存泄漏
  private destroy$ = new Subject<void>();

  constructor(
    private store: Store,
    private elementRef: ElementRef<HTMLInputElement>,
    // 可选注入MatSelect,只有指令用在mat-select上时才会有实例
    @Optional() private matSelect: MatSelect
  ) {}

  ngOnInit(): void {
    // 判断当前是否挂载在mat-select组件上
    if (this.matSelect) {
      // 监听mat-select的selectionChange事件
      this.matSelect.selectionChange
        .pipe(takeUntil(this.destroy$))
        .subscribe(event => {
          this.store.dispatch<IAction<IAdjust>>({
            type: RDX_DELIVERY_ACROSS_ADJUST,
            payload: {
              key: this.key,
              // 直接从事件中拿到选中值
              value: event.value
            },
            component: this.component
          })
        })
    }
  }

  // 原有逻辑保留,用于原生input的change事件监听
  @HostListener('change') onChange() {
    // 仅当不是mat-select场景时走原有逻辑,避免重复触发
    if (!this.matSelect) {
      this.store.dispatch<IAction<IAdjust>>({
        type: RDX_DELIVERY_ACROSS_ADJUST,
        payload: {
          key: this.key,
          value: this.elementRef.nativeElement.value
        },
        component: this.component
      })
    }
  }

  ngOnDestroy(): void {
    this.destroy$.next();
    this.destroy$.complete();
  }
}

修改后不需要改动你原有组件的模板代码,指令可以同时适配原生input和mat-select两种使用场景。

内容的提问来源于stack exchange,提问作者Noah Bergh

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.05 12:09:03