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

Angular实现下拉框选中项移除、删标签后恢复选项的方法

Angular 实现下拉选择与标签双向联动效果

实现目标

下拉选择组件选中选项后自动生成对应标签,需补充两个交互规则:

  • 选项被选中后自动从下拉列表移除,避免重复选择
  • 已生成的标签被删除时,对应选项自动恢复到下拉列表,支持再次选择

效果示意图


核心实现思路

不直接用传入的全量选项渲染下拉列表,单独维护一份实时可选选项列表,始终保证:
可选选项 = 全量选项 - 已生成标签对应的选项
每次选中选项、删除标签时同步更新这份可选列表即可。


具体代码实现

1. 组件类(TS)调整

import { Component, Input, OnInit, OnDestroy } from '@angular/core';
import { BehaviorSubject, Observable, Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';

export class SelectWithTagInputComponent implements OnInit, OnDestroy {
  @Input() filteredProperty: EnumRowConfigDto;
  @Input() inputOptions: Observable<IOption[]>;
  @Input() labelFilter: string;

  defaultSelectedValue = null;
  // 下拉框实际渲染的可选选项流
  availableOptions$ = new BehaviorSubject<IOption[]>([]);
  // 全量选项备份,用于计算可选列表
  private allOptions: IOption[] = [];
  // 销毁订阅用
  private destroy$ = new Subject<void>();

  ngOnInit(): void {
    // 订阅全量选项数据源,初始化可选列表
    this.inputOptions
      .pipe(takeUntil(this.destroy$))
      .subscribe(allOpts => {
        this.allOptions = allOpts;
        this.updateAvailableOptions();
      });
  }

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

  // 下拉选中事件
  selectedOption(value): void {
    let filterData;
    if (typeof value === 'string') {
      filterData = JSON.parse(value);
      filterData.name = filterData.value;
      delete filterData.value;
    } else {
      filterData = value;
    }

    // 避免重复添加标签
    const hasExisted = this.filteredProperty.filters.some(el => el.name === filterData.name);
    if (!hasExisted) {
      this.filteredProperty.filters.push(filterData);
      // 添加标签后更新可选列表,移除已选选项
      this.updateAvailableOptions();
    }

    // 重置下拉框到默认提示项
    this.defaultSelectedValue = null;
  }

  // 标签删除回调
  setDefaultOptionSelect(): void {
    this.defaultSelectedValue = null;
    // 删除标签后更新可选列表,恢复对应选项
    this.updateAvailableOptions();
  }

  // 计算当前可选选项:过滤掉已生成标签的选项
  private getAvailableOptions(): IOption[] {
    const selectedValues = this.filteredProperty.filters.map(item => item.name);
    return this.allOptions.filter(opt => !selectedValues.includes(opt.value));
  }

  // 推送最新可选选项到视图
  private updateAvailableOptions(): void {
    this.availableOptions$.next(this.getAvailableOptions());
  }
}

// 类型定义(可根据项目实际类型调整)
interface IOption {
  label: string;
  value: string | number;
}
interface EnumDto {
  name: string | number;
  label: string;
}
interface EnumRowConfigDto {
  filters: EnumDto[];
}

2. 模板(HTML)调整

仅需要把下拉框的选项循环源从原来的inputOptions | async替换为我们维护的availableOptions$ | async,标签组件部分原有逻辑无需改动:

<select class="form-control" 
        id="{{labelFilter | removewhitespaces}}" 
        name="{{labelFilter | removewhitespaces}}"
        [(ngModel)]="defaultSelectedValue"
        (change)="selectedOption($event.target['value'])">
  <option [value]="null" disabled selected>{{labelFilter}}</option>
  <!-- 绑定过滤后的可选选项列表 -->
  <option *ngFor="let option of availableOptions$ | async"
          [value]="option | json">
    {{option.label}}
  </option>
</select>

<tag-input *ngIf="filteredProperty.filters.length"
           [(ngModel)]="filteredProperty.filters"
           [class.full-width]="filteredProperty.filters.length"
           (onRemove)="setDefaultOptionSelect()"
           [identifyBy]="'name'"
           [displayBy]="'label'"
           [placeholder]="''"
           [secondaryPlaceholder]="''">
</tag-input>

补充说明:如果全量选项是动态变更的(比如从接口拉取、搜索过滤),只需要在全量选项更新后调用updateAvailableOptions()重新计算可选列表即可,逻辑可直接复用。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.31 21:18:20