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

Angular中FormArray表格排序失效及MatTable改造咨询

问题原因及解决方案

为什么MatSort失效?

MatSort是Angular Material专为MatTable设计的配套指令,你用普通表格+FormArray循环渲染的方式,既没把表格和MatSort指令绑定,也没让数据源和MatSort建立关联逻辑,自然触发不了排序功能。MatSort的排序逻辑依赖MatTable的数据源(比如MatTableDataSource)监听排序事件、重新计算数据顺序并更新视图,普通表格不具备这些机制。

是否需要改用MatTable?

是的,想要复用MatSort的内置排序能力,必须切换到MatTable组件。它能和MatSort、MatPaginator等组件无缝整合,同时完全支持带输入框的编辑场景,不用放弃增删改功能。

改造实现带输入框的可排序MatTable

步骤1:组件类配置

在组件中准备FormArray和MatTableDataSource,同时获取MatSort实例:

import { Component, ViewChild, OnInit } from '@angular/core';
import { FormBuilder, FormArray } from '@angular/forms';
import { MatTableDataSource } from '@angular/material/table';
import { MatSort } from '@angular/material/sort';

interface Book {
  Id: number;
  Title: string;
  Description: string;
}

@Component({
  selector: 'app-book-table',
  templateUrl: './book-table.component.html',
  styleUrls: ['./book-table.component.css']
})
export class BookTableComponent implements OnInit {
  displayedColumns: string[] = ['id', 'title', 'description', 'actions'];
  bookFormArray: FormArray;
  dataSource: MatTableDataSource<Book>;

  @ViewChild(MatSort) sort!: MatSort;

  constructor(private fb: FormBuilder) {
    // 初始化示例数据
    const initialBooks: Book[] = [
      { Id: 1, Title: 'Book 1', Description: 'Desc 1' },
      { Id: 2, Title: 'Book 2', Description: 'Desc 2' }
    ];
    // 将初始数据转为FormArray
    this.bookFormArray = this.fb.array(
      initialBooks.map(book => this.fb.group({
        Id: book.Id,
        Title: book.Title,
        Description: book.Description
      }))
    );
    // 初始化数据源
    this.dataSource = new MatTableDataSource(initialBooks);
  }

  ngOnInit(): void {
    // 关联MatSort和数据源
    this.dataSource.sort = this.sort;

    // 监听FormArray变化,同步更新数据源(确保排序后编辑的数据能同步)
    this.bookFormArray.valueChanges.subscribe(values => {
      this.dataSource.data = values;
    });
  }

  // 获取FormArray的控件
  get bookControls() {
    return this.bookFormArray.controls as FormArray[];
  }

  // 添加书籍
  addBook() {
    const newBook: Book = { Id: Date.now(), Title: '', Description: '' };
    this.bookFormArray.push(this.fb.group(newBook));
    this.dataSource.data = [...this.dataSource.data, newBook];
  }

  // 删除书籍
  deleteBook(index: number) {
    this.bookFormArray.removeAt(index);
    this.dataSource.data = this.dataSource.data.filter((_, i) => i !== index);
  }
}

步骤2:模板配置

在模板中使用MatTable、MatSort,并在列中添加输入框绑定FormControl:

<div class="container">
  <button mat-raised-button color="primary" (click)="addBook()">添加书籍</button>

  <table mat-table [dataSource]="dataSource" matSort class="mt-4">
    <!-- ID列 -->
    <ng-container matColumnDef="id">
      <th mat-header-cell *matHeaderCellDef mat-sort-header>ID</th>
      <td mat-cell *matCellDef="let element; let i = index">
        <input type="number" [formControl]="bookControls[i].get('Id')">
      </td>
    </ng-container>

    <!-- 标题列 -->
    <ng-container matColumnDef="title">
      <th mat-header-cell *matHeaderCellDef mat-sort-header>标题</th>
      <td mat-cell *matCellDef="let element; let i = index">
        <input type="text" [formControl]="bookControls[i].get('Title')">
      </td>
    </ng-container>

    <!-- 描述列 -->
    <ng-container matColumnDef="description">
      <th mat-header-cell *matHeaderCellDef mat-sort-header>描述</th>
      <td mat-cell *matCellDef="let element; let i = index">
        <input type="text" [formControl]="bookControls[i].get('Description')">
      </td>
    </ng-container>

    <!-- 操作列 -->
    <ng-container matColumnDef="actions">
      <th mat-header-cell *matHeaderCellDef>操作</th>
      <td mat-cell *matCellDef="let element; let i = index">
        <button mat-icon-button color="warn" (click)="deleteBook(i)">
          <mat-icon>delete</mat-icon>
        </button>
      </td>
    </ng-container>

    <tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
    <tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
  </table>
</div>

关键注意点

  • 确保在AppModule中导入MatTableModule、MatSortModule、MatButtonModule、MatIconModule等必要模块;
  • 数据源dataSource和FormArray要保持同步,避免排序后编辑的数据和视图不一致;
  • 用mat-sort-header标记需要排序的表头,点击表头就能触发排序。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.25 20:55:26