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

Angular Material中mat-chip无法根据FormControl初始值渲染的问题

解决Angular Material多选Select初始值Mat-Chip不渲染的问题

我帮你排查了下代码,发现几个关键问题导致初始值的mat-chip没正常渲染,咱们一步步来解决:

问题根源

  1. 对象引用不匹配:你初始化FormControl用的是[{ id: 1, name: "Extra cheese" }],这是一个全新的对象;而5秒后异步加载的toppingList$里的{ id: 1, name: "Extra cheese" }是另一个不同引用的对象。Angular Material的多选mat-select默认用对象引用相等来匹配选中项,所以即使内容一样,也不会被识别为有效选中项,进而影响trigger里chip的渲染。
  2. 变更检测时机:初始时toppingList$还没返回数据,mat-select没有可选项,这时候mat-select-trigger的内容可能不会被正确触发渲染,哪怕FormControl已经有值。
  3. 类型错误:onToppingRemoved方法里错误地把对象数组当成字符串数组处理,这会导致移除功能失效,后续操作也会出问题。

修复后的代码

TS代码

import { Component, OnInit } from '@angular/core';
import { FormControl } from '@angular/forms';
import { Subject } from 'rxjs';

export class SelectMultipleExample implements OnInit {
  private test = new Subject<{ id: number; name: string }[]>();
  toppingList$ = this.test.asObservable();
  toppingsControl = new FormControl<{ id: number; name: string }[]>([]); // 明确类型

  constructor() {}

  ngOnInit(): void {
    // 模拟异步加载选项
    setTimeout(() => {
      const toppingList = [
        { id: 1, name: "Extra cheese" },
        { id: 2, name: "Mushroom" }
      ];
      this.test.next(toppingList);
      
      // 从加载的选项中匹配初始值(用id匹配,避免引用问题)
      const initialTopping = toppingList.find(t => t.id === 1);
      if (initialTopping) {
        this.toppingsControl.setValue([initialTopping]);
      }
    }, 5000);
  }

  onToppingRemoved(topping: { id: number; name: string }) {
    // 正确处理对象数组
    const currentToppings = [...this.toppingsControl.value]; // 拷贝数组,避免直接修改原数组
    const index = currentToppings.findIndex(t => t.id === topping.id);
    if (index !== -1) {
      currentToppings.splice(index, 1);
      this.toppingsControl.setValue(currentToppings);
    }
  }
}

HTML代码

<mat-form-field>
  <mat-label>Toppings</mat-label>
  <mat-select [formControl]="toppingsControl" multiple>
    <mat-select-trigger>
      <mat-chip-list>
        <!-- 确保遍历的是FormControl的有效值,添加空值判断 -->
        <mat-chip *ngFor="let topping of toppingsControl.value || []" [removable]="true" (removed)="onToppingRemoved(topping)">
          {{ topping.name }}
          <mat-icon matChipRemove>cancel</mat-icon>
        </mat-chip>
      </mat-chip-list>
    </mat-select-trigger>
    <mat-option *ngFor="let topping of toppingList$ | async" [value]="topping">{{topping.name}}</mat-option>
  </mat-select>
</mat-form-field>
<br/>
{{ toppingsControl?.value | json }}

关键修改点说明

  • 解决引用问题:在异步加载选项后,从返回的选项数组里找到匹配id的对象,再设置给FormControl,这样选中值和选项的引用一致,mat-select能正确识别。
  • 明确类型:给FormControl指定明确的泛型类型,避免类型错误,同时让代码更清晰。
  • 安全遍历:在*ngFor里添加|| [],确保当FormControl值为空时不会报错,同时保证chip列表能正确渲染。
  • 修复移除逻辑:用findIndex通过id匹配对象,而不是indexOf(依赖引用),这样即使引用不同,只要id一致就能正确移除,同时拷贝数组再修改,避免直接操作FormControl的原数组值。

这样修改后,初始值的mat-chip就能在选项加载后正常渲染,移除功能也能正常工作啦!

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.07 19:17:47