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

多个ng-select组件数据同步:实现选中项在其他选择器隐藏

解决方案:ng-select选中项在其他选择器隐藏

核心思路

不能直接过滤原数组,要为每个select维护排除自身选中项后的可用列表,同时监听所有select的选中变化,实时更新其他select的可用选项。

步骤1:父组件改造(使用app-selector的组件)

  1. 跟踪所有select的选中值集合
  2. 为每个select生成过滤后的items(排除其他select已选的项)
  3. 监听每个formControl的变化,更新全局选中集合
import { Component, OnInit } from '@angular/core';
import { FormBuilder, FormGroup } from '@angular/forms';

@Component({
  selector: 'app-parent-component',
  templateUrl: './parent-component.component.html'
})
export class ParentComponent implements OnInit {
  levels = [1, 2, 3]; // 示例层级
  users = [
    { id: 1, name: '张三' },
    { id: 2, name: '李四' },
    { id: 3, name: '王五' },
    { id: 4, name: '赵六' }
  ];
  form: FormGroup;
  selectedUserIds: Set<number> = new Set(); // 存储所有已选用户ID

  constructor(private fb: FormBuilder) {}

  ngOnInit(): void {
    // 初始化表单
    const formControls = this.levels.reduce((controls, level) => {
      controls[`usersOnLevel${level}`] = this.fb.control([]);
      return controls;
    }, {} as Record<string, any>);
    this.form = this.fb.group(formControls);

    // 监听所有表单控件变化,更新全局选中集合
    Object.keys(this.form.controls).forEach(controlName => {
      this.form.get(controlName)?.valueChanges.subscribe(selectedIds => {
        // 先移除当前控件之前的选中项
        const prevValue = this.form.get(controlName)?.value || [];
        prevValue.forEach((id: number) => this.selectedUserIds.delete(id));
        // 添加当前控件新选中的项
        selectedIds.forEach((id: number) => this.selectedUserIds.add(id));
      });
    });
  }

  // 为每个select获取过滤后的items:排除其他select已选的项,但保留自身已选的
  getFilteredUsers(controlName: string): any[] {
    const currentSelected = this.form.get(controlName)?.value || [];
    return this.users.filter(user => {
      // 如果当前用户在自身已选中,保留;否则检查是否被其他select选中
      return currentSelected.includes(user.id) || !this.selectedUserIds.has(user.id);
    });
  }
}

步骤2:父组件模板修改

将原固定的[items]='users'替换为动态过滤后的列表,无需额外自定义optionTemplate(若需自定义,直接基于过滤后的列表渲染即可)

<form [formGroup]="form">
  <div *ngFor="let level of levels">
    <app-selector class="mb-4"
      [multiple]="true"
      [hideSelected]="true"
      [bindLabel]="'name'"
      [bindValue]="'id'"
      [items]="getFilteredUsers('usersOnLevel'+level)"
      [formControlName]="'usersOnLevel'+level">

      <ng-template ng-label-tmp let-item='item' let-clear='clear' #labelTemplate>
        <span class='ng-value-label cursor-pointer'> {{ item.name }}</span>
        <span class='ng-value-icon right' (click)='clear(item)' aria-hidden='true'>×</span>
      </ng-template>
      
    </app-selector>
  </div>
</form>

原方案无效原因说明

你之前尝试给items添加hasBeenSelected属性未生效,主要问题在于:

  • 直接修改原数组属性后,未触发Angular变更检测,视图未更新
  • 所有select绑定同一数组引用,修改属性后无法区分“自身选中”和“其他选中”的项,导致逻辑混乱

上述方案通过为每个select生成独立的过滤列表,既保留自身已选项,又隐藏其他select的已选项,完美匹配需求。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.26 05:01:00