Mat-table排序演示不起作用

ave*_*ern 78 angular-material angular

我试图让mat-table排序在本地工作,虽然我可以按预期显示数据,但点击标题行不会像在线示例那样进行排序(根本不会发生任何事情).我试图让这个演示在本地工作:https : //material.angular.io/components/sort/overview https://plnkr.co/edit/XF5VxOSEBxMTd9Yb3ZLA?p=preview

我使用Angular CLI生成了一个新项目,然后按照以下步骤操作:https: //material.angular.io/guide/getting-started

这是我的本地文件:

app.module.ts

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { MatSort, MatTableModule } from '@angular/material';

import { AppComponent } from './app.component';
import { TableSortingExample } from './table-sorting-example';

@NgModule({
  declarations: [
    AppComponent,
    TableSortingExample,
    MatSort
  ],
  imports: [
    BrowserModule,
    MatTableModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }
Run Code Online (Sandbox Code Playgroud)

app.component.ts

import { Component } from '@angular/core';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  title = 'app';
}
Run Code Online (Sandbox Code Playgroud)

app.component.html

<div style="text-align:center">
  <h1>
    Welcome to {{title}}!
  </h1>
  <table-sorting-example></table-sorting-example>
</div>
Run Code Online (Sandbox Code Playgroud)

表分拣example.html的

<div class="example-container mat-elevation-z8">
  <mat-table #table [dataSource]="dataSource" matSort>

    <!--- Note that these columns can be defined in any order.
          The actual rendered columns are set as a property on the row definition" -->

    <!-- ID Column -->
    <ng-container matColumnDef="userId">
      <mat-header-cell *matHeaderCellDef mat-sort-header> ID </mat-header-cell>
      <mat-cell *matCellDef="let row"> {{row.id}} </mat-cell>
    </ng-container>

    <!-- Progress Column -->
    <ng-container matColumnDef="progress">
      <mat-header-cell *matHeaderCellDef mat-sort-header> Progress </mat-header-cell>
      <mat-cell *matCellDef="let row"> {{row.progress}}% </mat-cell>
    </ng-container>

    <!-- Name Column -->
    <ng-container matColumnDef="userName">
      <mat-header-cell *matHeaderCellDef mat-sort-header> Name </mat-header-cell>
      <mat-cell *matCellDef="let row"> {{row.name}} </mat-cell>
    </ng-container>

    <!-- Color Column -->
    <ng-container matColumnDef="color">
      <mat-header-cell *matHeaderCellDef mat-sort-header> Color </mat-header-cell>
      <mat-cell *matCellDef="let row" [style.color]="row.color"> {{row.color}} </mat-cell>
    </ng-container>

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


<!-- Copyright 2017 Google Inc. All Rights Reserved.
    Use of this source code is governed by an MIT-style license that
    can be found in the LICENSE file at http://angular.io/license -->
Run Code Online (Sandbox Code Playgroud)

表分拣example.ts

import {Component, ViewChild} from '@angular/core';
import {DataSource} from '@angular/cdk/collections';
import {MatSort} from '@angular/material';
import {BehaviorSubject} from 'rxjs/BehaviorSubject';
import {Observable} from 'rxjs/Observable';
import 'rxjs/add/operator/startWith';
import 'rxjs/add/observable/merge';
import 'rxjs/add/operator/map';

/**
 * @title Table with sorting
 */
@Component({
  selector: 'table-sorting-example',
  styleUrls: ['table-sorting-example.css'],
  templateUrl: 'table-sorting-example.html',
})
export class TableSortingExample {
  displayedColumns = ['userId', 'userName', 'progress', 'color'];
  exampleDatabase = new ExampleDatabase();
  dataSource: ExampleDataSource | null;

  @ViewChild(MatSort) sort: MatSort;

  ngOnInit() {
    this.dataSource = new ExampleDataSource(this.exampleDatabase, this.sort);
  }
}

/** Constants used to fill up our data base. */
const COLORS = ['maroon', 'red', 'orange', 'yellow', 'olive', 'green', 'purple',
  'fuchsia', 'lime', 'teal', 'aqua', 'blue', 'navy', 'black', 'gray'];
const NAMES = ['Maia', 'Asher', 'Olivia', 'Atticus', 'Amelia', 'Jack',
  'Charlotte', 'Theodore', 'Isla', 'Oliver', 'Isabella', 'Jasper',
  'Cora', 'Levi', 'Violet', 'Arthur', 'Mia', 'Thomas', 'Elizabeth'];

export interface UserData {
  id: string;
  name: string;
  progress: string;
  color: string;
}

/** An example database that the data source uses to retrieve data for the table. */
export class ExampleDatabase {
  /** Stream that emits whenever the data has been modified. */
  dataChange: BehaviorSubject<UserData[]> = new BehaviorSubject<UserData[]>([]);
  get data(): UserData[] { return this.dataChange.value; }

  constructor() {
    // Fill up the database with 100 users.
    for (let i = 0; i < 100; i++) { this.addUser(); }
  }

  /** Adds a new user to the database. */
  addUser() {
    const copiedData = this.data.slice();
    copiedData.push(this.createNewUser());
    this.dataChange.next(copiedData);
  }

  /** Builds and returns a new User. */
  private createNewUser() {
    const name =
      NAMES[Math.round(Math.random() * (NAMES.length - 1))] + ' ' +
      NAMES[Math.round(Math.random() * (NAMES.length - 1))].charAt(0) + '.';

    return {
      id: (this.data.length + 1).toString(),
      name: name,
      progress: Math.round(Math.random() * 100).toString(),
      color: COLORS[Math.round(Math.random() * (COLORS.length - 1))]
    };
  }
}

/**
 * Data source to provide what data should be rendered in the table. Note that the data source
 * can retrieve its data in any way. In this case, the data source is provided a reference
 * to a common data base, ExampleDatabase. It is not the data source's responsibility to manage
 * the underlying data. Instead, it only needs to take the data and send the table exactly what
 * should be rendered.
 */
export class ExampleDataSource extends DataSource<any> {
  constructor(private _exampleDatabase: ExampleDatabase, private _sort: MatSort) {
    super();
  }

  /** Connect function called by the table to retrieve one stream containing the data to render. */
  connect(): Observable<UserData[]> {
    const displayDataChanges = [
      this._exampleDatabase.dataChange,
      this._sort.sortChange,
    ];

    return Observable.merge(...displayDataChanges).map(() => {
      return this.getSortedData();
    });
  }

  disconnect() {}

  /** Returns a sorted copy of the database data. */
  getSortedData(): UserData[] {
    const data = this._exampleDatabase.data.slice();
    if (!this._sort.active || this._sort.direction == '') { return data; }

    return data.sort((a, b) => {
      let propertyA: number|string = '';
      let propertyB: number|string = '';

      switch (this._sort.active) {
        case 'userId': [propertyA, propertyB] = [a.id, b.id]; break;
        case 'userName': [propertyA, propertyB] = [a.name, b.name]; break;
        case 'progress': [propertyA, propertyB] = [a.progress, b.progress]; break;
        case 'color': [propertyA, propertyB] = [a.color, b.color]; break;
      }

      let valueA = isNaN(+propertyA) ? propertyA : +propertyA;
      let valueB = isNaN(+propertyB) ? propertyB : +propertyB;

      return (valueA < valueB ? -1 : 1) * (this._sort.direction == 'asc' ? 1 : -1);
    });
  }
}


/**  Copyright 2017 Google Inc. All Rights Reserved.
 Use of this source code is governed by an MIT-style license that
 can be found in the LICENSE file at http://angular.io/license */
Run Code Online (Sandbox Code Playgroud)

有没有人知道为什么它会像在线表一样出现但缺乏排序功能?

ave*_*ern 165

对于任何可能遇到此问题的人:问题是我没有在角度材料网站上正确阅读API参考,该部分说我必须导入MatSortModule.我将app.module.ts中的导入列表更改

imports: [
    BrowserModule,
    MatTableModule,
    MatSortModule
  ],
Run Code Online (Sandbox Code Playgroud)

它工作得很好

  • 在文档中没有提到这个模块.https://material.angular.io/components/table/overview#sorting我也浪费了一个小时. (38认同)
  • 我已经导入了 `MatSortModule` 和 `BrowserAnimationsModule`,并且我已经确保 matColumnDef 值与属性名称匹配,但我仍然无法让它做任何事情。 (9认同)
  • 这很好,在标题文本中是可点击的,图标也在那里,但仍然排序不起作用. (4认同)
  • 检查 app.module.ts 中是否也导入了 `BrowserAnimationsModule` (3认同)
  • 我可以说他们是SOB吗?我花了1个小时试图找出我的ViewChild无法正常工作的原因.他们不能从MatTableModule导入/导出这个MatSortModule吗? (2认同)

And*_*sta 84

我有一个问题,排序功能正在运行,但它没有正确排序.我意识到必须matColumnDef具有class / interface我所引用的属性的相同名称matCellDef.

根据Angular Material 文档:

默认情况下,MatTableDataSource在假设已排序列的名称与列显示的数据属性名称匹配的情况下进行排序.

举个例子:

<ng-container matColumnDef="name"> 
    <mat-header-cell *matHeaderCellDef mat-sort-header> NAME </mat-header-cell>
    <mat-cell *matCellDef="let row"> {{row.name}} </mat-cell>
</ng-container>
Run Code Online (Sandbox Code Playgroud)

namematColumnDef指令必须是一样的name在所使用的<mat-cell>组件.

  • @Suyog,/sf/answers/3434024541/。 (3认同)
  • 我使用“Id”作为列名,而实体使用“id”。案例差异使其无法运行(由于重构未命中)。现在它解决了。谢谢 (2认同)
  • 谢谢,这非常有用。 (2认同)
  • @NitinSingh,如果您需要在“element”上调用函数怎么办,比如“{{row.getName()}}” (2认同)

小智 38

如果表位于* ngIf内,则它将无法正常工作。如果将其更改为[hidden],它将起作用

  • !!!您保存我的一天!使用&lt;div [hidden] =“!xxx”&gt;代替`&lt;div * ngIf =“ xxx”&gt; (11认同)
  • 该解决方案对我有用。谢谢,@aungye,但是,只是想知道是什么触发了 *ngIf 的这个问题,有什么想法吗? (5认同)
  • 或者只是在 ngAfterViewInit 而不是 ngOnInit 中设置数据源 (3认同)
  • 这是最可能发生的“隐藏”问题,感谢您的解决方案!文件可能已经警告过这一点 (2认同)
  • [hidden] 仍然为表格保留空间,因此大多数时候这不是一个好的解决方案 (2认同)

Emm*_*mmy 26

MatSort 可能不起作用的原因之一是在this.dataSource.sort = this.sort定义之前将其添加到数据源(即)。这可能有多种原因:

  1. 如果在 ngOnInit 中添加排序。此时模板尚未呈现,因此您获得的 MatSort@ViewChild(MatSort, { static: true }) sort: MatSort;是未定义的,可以理解的是不会执行任何操作。此问题的解决方案是移至this.dataSource.sort = sortngAfterViewInit。当调用 ngAfterViewInit 时,您的组件将被渲染,并且应该定义 MatSort。

  2. 当您使用 *ngIf 是您的表格元素上的模板时,或者如果它是父元素,并且此 *ngIf 会导致您的表格在您尝试设置 MatSort 时不呈现。例如,如果您有*ngIf="dataSource.data.length > 0"表格元素(仅在有数据存在时才渲染它)并且您this.dataSource.sort = this.sort在设置this.dataSource.data数据后立即设置。组件视图还不会重新渲染,因此 MatSort 仍将是未定义的。

为了让 MatSort 工作并仍然有条件地显示您的表格,您可以决定替换多个其他答案中所述的*ngIfwith [hidden]。但是,如果您想保留 *ngIf 语句,可以使用以下解决方案。这个解决方案适用于 Angular 9,我没有在以前的版本上测试过,所以我不确定它是否在那里工作。

我在这里找到了这个解决方案:https : //github.com/angular/components/issues/10205

而不是把:

@ViewChild(MatSort) sort: MatSort;
Run Code Online (Sandbox Code Playgroud)

对 matSort 使用 setter。一旦您的视图中的 matSort 更改(即第一次定义),此设置器将触发,当您通过单击箭头更改排序时,它不会触发。这将如下所示:

@ViewChild(MatSort) set matSort(sort: MatSort) {
    this.dataSource.sort = sort;
}
Run Code Online (Sandbox Code Playgroud)

如果您有其他功能(以编程方式)更改排序,我不确定它是否会再次触发,我还没有测试过。如果您不想确保它仅在未定义排序时设置排序,您可以执行以下操作:

@ViewChild(MatSort) set matSort(sort: MatSort) {
    if (!this.dataSource.sort) {
        this.dataSource.sort = sort;
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 谢谢,这个解决方案很完美。请注意,如果您的表有 *ngIf(例如,等待来自 API 的数据),则需要添加一个条件来检查“排序”是否存在。如果不这样做,您将在控制台上收到错误“无法设置未定义的属性‘排序’”。 (2认同)

Cha*_*san 21

在超时块中添加排序对我有用,

dataSource = new MatTableDataSource(this.articleService.getAllArticles());
setTimeout(() => {
  this.tableDataSource.sort = this.sort;
  this.tableDataSource.paginator = this.paginator;
});
Run Code Online (Sandbox Code Playgroud)

  • 确实是一种糟糕的做法。它之所以有效,是因为您在组件初始化后让一些时间过去,以便构建数据源,然后添加排序和分页器。最好的方法是在 ngOnInit 中移动 datSource 构建,然后在 AfterViewInit 中移动排序和分页器分配。这就是生命周期钩子存在的目的。 (6认同)

小智 20

matColumnDef名称和*matCellDef实际值名称应该相同

例:

<ng-container matColumnDef="oppNo">
    <th mat-header-cell *matHeaderCellDef mat-sort-header>Opportunity Number</th>
    <td mat-cell *matCellDef="let element">{{element.oppNo}}</td>
</ng-container>
Run Code Online (Sandbox Code Playgroud)

在我的情况下,oppNo对于matColumnDef名称和*matCellDef名称和排序工作正常.


ber*_*aks 16

我在这个问题上花了几个小时。在阅读了许多线程后,以下是我所做的步骤。

  1. 正如@avern 提到的,您需要导入MatSortModule.
  2. 确保您没有将表格包含在*ngIf. 将其更改[hidden]@zerg 推荐的。(我不明白为什么)

希望这可以帮助。


小智 8

我也遇到了这个问题。由于需要等待定义子项,因此必须实现和使用AfterViewInit,而不是onInit。

  ngAfterViewInit (){
    this.dataSource.sort = this.sort;
  }
Run Code Online (Sandbox Code Playgroud)

  • @尼古拉斯M。this.sort 字段通过“@ViewChild”注释绑定,此类字段在“ngAfterViewInit”中实例化,但尚未在“ngOnInit”中实例化 (2认同)

小智 8

在您的 app.module.ts 中,执行以下操作:

进口

import { MatSortModule } from '@angular/material/sort';
Run Code Online (Sandbox Code Playgroud)

然后加

imports: [
    ...
    MatSortModule
],
Run Code Online (Sandbox Code Playgroud)


kum*_*ama 7

我发现这个旧博客帮助我让它工作: https://www.jeffryhouser.com/index.cfm/2018/10/23/Five-Reasons-My-ngMaterial-Table-wont-sort

  1. 确保导入MatSortModule
  2. 指定matSort标题
  3. 确保将您的数据源包装在MatTableDataSource
    • 这是帮助我解决问题的(明白了吗?解决问题)。在模板中,我直接引用数组 ( <table mat-table [dataSource]="this.products" matSort>),但我应该使用在代码中初始化的数据源对象 ( <table mat-table [dataSource]="this.dataSource" matSort>)。数据源初始化如下dataSource = new MatTableDataSource(this.products)
  4. 告诉数据源您的排序,在ngOnInit/ngAfterViewInit
  5. 如果您不想使用,请编写自己的排序MatTableDataSource


小智 6

我的解决方案是修复几件事(基本上合并此页面中的大多数解决方案)。

检查事项:

  1. BrowserModule, MatTableModule, MatSortModule 模块应导入到根模块文件中。
  2. 确保使用过MatTableDatasource类并在其中传递数据数组作为参数
  3. 确保您的表未嵌套在*ngIf=....指令中。请改用其他条件操作(仍然不明白为什么)。


小智 6

我通过将表数据命名为与 *matColumnDef 相同的名称来修复此问题,例如:

<!-- Name Column -->
<ng-container matColumnDef="name">
  <mat-header-cell *matHeaderCellDef mat-sort-header> Name </mat-header-cell>
  <mat-cell *matCellDef="let row"> {{row.name}} </mat-cell>
</ng-container>
Run Code Online (Sandbox Code Playgroud)

反而

<!-- Name Column -->
    <ng-container matColumnDef="userName">
      <mat-header-cell *matHeaderCellDef mat-sort-header> Name </mat-header-cell>
      <mat-cell *matCellDef="let row"> {{row.name}} </mat-cell>
    </ng-container>
Run Code Online (Sandbox Code Playgroud)


Sha*_*tal 6

在花了几周时间在这上面之后。我发现你有以下情况

  1. 您需要在 app.module.ts 中导入 MatSortModule。
 imports: [
    ...
    MatSortModule
],
Run Code Online (Sandbox Code Playgroud)
<ng-container matColumnDef="ledgerTransactionCreditSum">
        <th mat-header-cell *matHeaderCellDef mat-sort-header> Ledger Transaction Credit </th>
        <td mat-cell *matCellDef="let element"> {{element.ledgerTransactionCreditSum}} </td>
    </ng-container>
 matColumnDef and element.ledgerTransactionCreditSum variable and matcolumn def shoulde be same
Run Code Online (Sandbox Code Playgroud)
  1. 在 ngViewInit 中定义排序和分页器
ngAfterViewInit(): void {
    this.dataSource.sort = this.sort;
    this.dataSource.paginator = this.paginator;
    this.dataSource.paginator?._changePageSize(400)
  }
Run Code Online (Sandbox Code Playgroud)


Raj*_*pan 5

我有两个问题。

  1. matColumnDef 和 matCellDef -> 名称不同
  2. 我正在从服务中获取数据。ngOnInit 排序不起作用。替换为

    ngAfterViewInit() { this.dataSource.sort = this.sort; }


WtF*_*dgE 5

对于那些对这些命名必须相等感到困惑的人,我做了一些测试:

这将起作用(属性的名称与列 def 相同):

<ng-container matColumnDef="version">
    <th mat-header-cell *matHeaderCellDef mat-sort-header> Version </th>
    <td mat-cell *matCellDef="let element"> {{element.version}} </td>
</ng-container>

displayedColumns: string[] = ['version']
Run Code Online (Sandbox Code Playgroud)

这不起作用(属性的名称与列 def 不同):

<ng-container matColumnDef="version2">
    <th mat-header-cell *matHeaderCellDef mat-sort-header> Version </th>
    <td mat-cell *matCellDef="let element"> {{element.version}} </td>
</ng-container>

displayedColumns: string[] = ['version2']
Run Code Online (Sandbox Code Playgroud)

仅供参考,这也不起作用(属性的长度):

<ng-container matColumnDef="length">
    <th mat-header-cell *matHeaderCellDef mat-sort-header> Version </th>
    <td mat-cell *matCellDef="let element"> {{element.ids.length}} </td>
</ng-container>

displayedColumns: string[] = ['length']
Run Code Online (Sandbox Code Playgroud)

这也不是:

<ng-container matColumnDef="ids.length">
    <th mat-header-cell *matHeaderCellDef mat-sort-header> Version </th>
    <td mat-cell *matCellDef="let element"> {{element.ids.length}} </td>
</ng-container>

displayedColumns: string[] = ['ids.length']
Run Code Online (Sandbox Code Playgroud)


小智 5

mat-sort 和 mat-paginator 不起作用的主要原因是

  1. 模块 MatSortModule 和 MatPaginatorModule 未导入
  2. 表处于 *ngIf 条件下
  3. matColumnDef 应与 matCellDef 和 displayedColumns 数组相同。