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

Angular Material Chips字段无法随表单提交问题求助

问题:Angular Material Chips字段无法随表单提交

问题描述

我搭建了一个表单,所有字段均可正常提交,但用于填写Technologies的Angular Material Chips(类似其他框架的标签组件)字段无法随表单提交。

HTML代码

<!--MAIN CONTAINER-->
<div class="container">
    <div class="row">
        <div class="col">
            <!--RESUME FORM-->
            <mat-card class="">
                <mat-card-content>
                    <form #resumeForm="ngForm" (ngSubmit)="submit(resumeForm)" class="m-3">
                        <mat-form-field>
                            <mat-label>Full Name</mat-label>
                            <input matInput type="text" [(ngModel)]="resume.fullname" name="fullname" disabled="true">
                        </mat-form-field>
                        <mat-form-field>
                            <mat-label>Current Role</mat-label>
                            <input matInput type="text" [(ngModel)]="resume.currentRole" name="currentRole">
                        </mat-form-field>
                        <mat-form-field>
                            <mat-label>Email</mat-label>
                            <input matInput type="text" [(ngModel)]="resume.email" name="email" disabled="true">
                        </mat-form-field>
                        <mat-form-field>
                            <mat-label>Description</mat-label>
                            <textarea matInput [(ngModel)]="resume.description" name="description"></textarea>
                        </mat-form-field>

                        <!--TECHNOLOGIES FIELD-->
                        <mat-form-field>
                            <mat-label>Technologies</mat-label>
                            <mat-chip-grid #chipGridTech>
                                <mat-chip-row *ngFor="let tech of techs" (removed)="removeTech(tech)">
                                    {{ tech }}
                                    <button matChipRemove>
                                        <mat-icon>cancel</mat-icon>
                                    </button>
                                </mat-chip-row>
                            </mat-chip-grid>
                            <input #techInput matInput type="text" [(ngModel)]="resume.technologies"
                                placeholder="add new technology..." [formControl]="techControl"
                                [matAutocomplete]="autoComplete" [matChipInputFor]="chipGridTech"
                                [matChipInputSeparatorKeyCodes]="separatorKeysCodesTech"
                                (matChipInputTokenEnd)="addTech($event)" name="technologies" />
                            <mat-autocomplete #autoComplete (optionSelected)="selectTech($event)">
                                <mat-option *ngFor="let tech of filteredTechs | async">
                                    {{ tech }}
                                </mat-option>
                            </mat-autocomplete>
                        </mat-form-field>

                        <!--CERTIFICATIONS FIELD-->
                        <mat-form-field>
                            <mat-label>Certifications</mat-label>
                            <input matInput type="text" [(ngModel)]="resume.certifications" name="certifications">
                        </mat-form-field>

                        <!--WORK EXPERIENCE FIELD-->
                        <mat-form-field>
                            <mat-label>Work Experience</mat-label>
                            <input matInput type="text" [(ngModel)]="resume.workExperience" name="workExperience">
                        </mat-form-field>

                        <mat-form-field>
                            <mat-label>Education</mat-label>
                            <input matInput type="text" [(ngModel)]="resume.education" name="education">
                        </mat-form-field>
                        <button mat-raised-button color="primary">Submit</button>
                    </form>
                </mat-card-content>
            </mat-card>
        </div>
    </div>
</div>

提交函数

submit(resumeForm: any) {
    console.log(resumeForm);
}

控制台日志

提交表单后,控制台打印的表单数据中无technologies字段,其余字段(如fullname、currentRole等)均正常显示。

已尝试操作

  • 添加/移除matInput属性
  • 添加/移除[(ngModel)]="resume.technologies"绑定
  • 添加/移除name="technologies"属性

警告信息

控制台出现警告:在同一个表单字段上同时使用了ngModel和formControl。Angular v6已弃用在响应式表单指令中混用ngModel输入属性与ngModelChange事件的方式,该特性将在未来版本中移除。


解决方法

核心问题有两个:一是模板驱动表单(ngModel)与响应式表单(formControl)混用导致的数据同步异常;二是Chips的展示数组techs与绑定的resume.technologies未关联,提交时无法获取标签数据。

方案1:改用纯响应式表单(推荐)

移除ngModel相关绑定,用formControl统一管理,同时同步更新resume.technologies:

  1. 组件类中同步标签数组与resume对象:
import { FormControl } from '@angular/forms';
import { Observable } from 'rxjs';
import { startWith, map } from 'rxjs/operators';
import { MatChipInputEvent } from '@angular/material/chips';
import { MatAutocompleteSelectedEvent } from '@angular/material/autocomplete';

techs: string[] = [];
techControl = new FormControl('');
filteredTechs: Observable<string[]>;

ngOnInit() {
    // 初始化时将resume的technologies加载到标签数组
    this.techs = [...this.resume.technologies];
    // 保留原有的自动补全过滤逻辑
    this.filteredTechs = this.techControl.valueChanges.pipe(
        startWith(''),
        map(value => this._filter(value || ''))
    );
}

addTech(event: MatChipInputEvent) {
    const value = (event.value || '').trim();
    if (value) {
        this.techs.push(value);
        // 同步更新resume的technologies字段
        this.resume.technologies = [...this.techs];
    }
    event.chipInput!.clear();
    this.techControl.setValue('');
}

removeTech(tech: string) {
    const index = this.techs.indexOf(tech);
    if (index >= 0) {
        this.techs.splice(index, 1);
        this.resume.technologies = [...this.techs];
    }
}

selectTech(event: MatAutocompleteSelectedEvent) {
    const value = event.option.viewValue;
    if (!this.techs.includes(value)) {
        this.techs.push(value);
        this.resume.technologies = [...this.techs];
    }
    this.techControl.setValue('');
}

private _filter(value: string): string[] {
    // 保留原有的过滤逻辑
    const filterValue = value.toLowerCase();
    return this.allTechs.filter(tech => tech.toLowerCase().includes(filterValue));
}
  1. 修改HTML中的input,移除ngModel和name属性:
<input #techInput matInput type="text"
    placeholder="add new technology..." [formControl]="techControl"
    [matAutocomplete]="autoComplete" [matChipInputFor]="chipGridTech"
    [matChipInputSeparatorKeyCodes]="separatorKeysCodesTech"
    (matChipInputTokenEnd)="addTech($event)" />
  1. 提交时直接使用resume对象:
submit() {
    console.log(this.resume);
    // 直接提交this.resume即可获取完整数据
}

方案2:改用纯模板驱动表单

移除formControl绑定,统一用ngModel管理,同时让标签展示数组直接引用resume.technologies:

  1. 组件类中修改标签操作逻辑:
addTech(event: MatChipInputEvent) {
    const value = (event.value || '').trim();
    if (value) {
        this.resume.technologies.push(value);
    }
    event.chipInput!.clear();
}

removeTech(tech: string) {
    const index = this.resume.technologies.indexOf(tech);
    if (index >= 0) {
        this.resume.technologies.splice(index, 1);
    }
}

selectTech(event: MatAutocompleteSelectedEvent) {
    const value = event.option.viewValue;
    if (!this.resume.technologies.includes(value)) {
        this.resume.technologies.push(value);
    }
}
  1. 修改HTML中的Chips和input:
<!-- 修改Chips的遍历源 -->
<mat-chip-row *ngFor="let tech of resume.technologies" (removed)="removeTech(tech)">
    {{ tech }}
    <button matChipRemove>
        <mat-icon>cancel</mat-icon>
    </button>
</mat-chip-row>

<!-- 移除formControl属性 -->
<input #techInput matInput type="text" [(ngModel)]="resume.technologies"
    placeholder="add new technology..."
    [matAutocomplete]="autoComplete" [matChipInputFor]="chipGridTech"
    [matChipInputSeparatorKeyCodes]="separatorKeysCodesTech"
    (matChipInputTokenEnd)="addTech($event)" name="technologies" />

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.07 19:20:36