Angular中如何检测mat-select下拉菜单关闭时的选项变更
mat-select面板关闭时检测本次打开周期选择变更方案
核心逻辑非常直接:面板打开时存一份当时选中值的快照,面板关闭时把当前选中值和快照比对,就能知道中间有没有做过勾选/取消勾选操作,全选/反选的操作也能自动覆盖,不需要额外加监听。
第一步:修改组件TS代码
先在组件类里加一个存快照的变量,再改你现有的changeFilterEvent方法,补一个值比对的工具方法就行:
import { MatSelect } from '@angular/material/select'; // 补类型导入,避免用any // 组件类内加变量,存储面板打开时的选中值快照 private selectedSnapshot: any[] = []; changeFilterEvent(opened: boolean, select: MatSelect) { if (opened) { // 面板打开时,存下当前选中值的副本,注意不要直接赋值引用,不然快照会跟着后续选择动态变化 // 如果你的选项是带id的对象,推荐这里只存id数组,比对效率更高 const currentVal = this.marketDropdownMultiCtrl.value || []; this.selectedSnapshot = JSON.parse(JSON.stringify(currentVal)); return; } // 以下为面板关闭时的执行逻辑 const currentSelected = this.marketDropdownMultiCtrl.value || []; const isSelectionChanged = this.compareSelectedValues(this.selectedSnapshot, currentSelected); if (isSelectionChanged) { // 这里写检测到变更后的业务逻辑,比如触发列表筛选、提交查询参数等 console.log('本次打开面板修改了选项'); } } // 比对两次选中值是否存在差异 private compareSelectedValues(oldVal: any[], newVal: any[]): boolean { // 选中数量不一致,肯定有变更 if (oldVal.length !== newVal.length) return true; // 如果选项是对象,用唯一标识(比如id)比对;如果是字符串/数字基础类型,直接比本身值即可 const oldIdSet = new Set(oldVal.map(item => item?.id ?? item)); return newVal.some(item => !oldIdSet.has(item?.id ?? item)); }
第二步:模板可选优化
你现在的mat-select上写了两个重复的模板引用变量#select和#marketDropdownMultiSelect,删掉一个即可,不影响功能只是冗余,改完参考:
<mat-form-field class="job-filter" appearance="fill"> <mat-select #select [formControl]="marketDropdownMultiCtrl" placeholder="Market" [multiple]="true" (openedChange)="changeFilterEvent($event, select)"> <mat-option> <ngx-mat-select-search [showToggleAllCheckbox]="true" placeholderLabel="Search Market filter" noEntriesFoundLabel="'No results found'" (toggleAll)="toggleSelectAllMarket($event)" [toogleAllCheckboxTooltipPosition]="'above'" [toggleAllCheckboxChecked]="marketDropdownMultiCtrl?.value?.length === marketDropdownSize" [toggleAllCheckboxIndeterminate]="marketDropdownMultiCtrl?.value?.length > 0 && marketDropdownMultiCtrl?.value?.length < marketDropdownSize" [toggleAllCheckboxTooltipMessage]="'Select / Deselect all Market filters'" [formControl]="marketDropdownMultiFilterCtrl"> </ngx-mat-select-search> </mat-option> <mat-option *ngFor="let market of filteredMarketListMulti | async" [value]="market"> {{market.description}} </mat-option> </mat-select> </mat-form-field>
界面效果参考:
注意点
- 如果你的选项值是字符串、数字这类基础类型,比对逻辑可以简化成
JSON.stringify([...oldVal].sort()) !== JSON.stringify([...newVal].sort()),不用单独写比对方法 - 不要直接监听formControl的
valueChanges事件判断变更,这个事件不管面板开没开只要值变就会触发,没法区分是本次打开面板操作的变更,还是代码初始化赋值、回填数据触发的变更,快照方案逻辑更干净性能也更好 - 存快照的时候如果只存选项唯一标识(比如id),不需要用
JSON.parse(JSON.stringify())深拷贝,直接浅拷贝数组就行:this.selectedSnapshot = [...currentVal.map(i => i.id)]
内容的提问来源于stack exchange,提问作者Diya Agastya
相关产品推荐
相关产品推荐

