排序演示不工作

我正在尝试让 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

这是我的本地文件:

应用程序模块

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 { }

应用程序组件

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


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

App.Component. html

<div style="text-align:center">
<h1>
Welcome to {{title}}!
</h1>
<table-sorting-example></table-sorting-example>
</div>

表-排序-示例. 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 -->

表-排序-示例

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 */

有人知道为什么它会像在线表格一样显示,但缺乏排序功能吗?

163059 次浏览

对于其他可能有这个问题的人: 问题是我没有正确阅读角度材料网站上的 API 参考文件,那部分文件说我必须导入 MatSortModule。将 应用程序模块中的导入列表更改为

imports: [
BrowserModule,
MatTableModule,
MatSortModule
],

效果很好

我遇到了一个问题,排序函数正在工作,但它没有正确地排序。我意识到 matColumnDef必须与我在 matCellDef中引用的 class / interface属性的名称相同。

根据角度材料 文件:

默认情况下,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>

matColumnDef指令中的 name必须与 <mat-cell>组件中使用的 name相同。

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>

在我的例子中,对于 matColumnDef name 和 * matCellDef name 以及排序,oppNo 是相同的。

在超时块中添加 sort 对我来说是可行的,

dataSource = new MatTableDataSource(this.articleService.getAllArticles());
setTimeout(() => {
this.tableDataSource.sort = this.sort;
this.tableDataSource.paginator = this.paginator;
});

如果你不想使用生命周期挂钩。

我也碰到了这个问题。因为需要等待子元素被定义,所以必须实现并使用 AfterViewInit,而不是 onInit。

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

如果表在里面 * ngIf,它就不会工作。 如果把它改为[隐藏] ,它就会工作

我的解决方案是修复几个问题(基本上是合并本页中的大多数解决方案)。

需要检查的事项:

  1. BrowserModule, MatTableModule, MatSortModule模块应该导入到根模块文件中。
  2. 确保使用了 MatTableDatasource类,并将数据数组作为参数传递给它
  3. 确保表没有嵌套在 *ngIf=....指令中。使用其他条件操作代替(仍然不明白为什么)。

对于我来说,用[ hide ]属性替换 mat-table 标签的 * ngIf 是可行的。 如何张贴这一个作为一个错误的角材料社区?

查看控制台中是否有任何 javascript 错误。可能是在初始化排序之前出现了其他错误。

在我的场景中,我通过使用与 * 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>

相反

<!-- 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>

如果您的表位于 * ngIf 中,并且您认为它与不对表进行排序有关,那么指定您自己的 sortingDataAccessor函数可能会解决这个问题,就像它对我所做的那样。我把我的桌子放在几个“ ngIfs”里面,把它从那些“ ngIfs”里面拿出来是没有意义的:

`ngAfterViewInit(): void {
this.matchesDataSource.sort = this.sort;
this.matchesDataSource.sortingDataAccessor = previewMatchSortingFn;
}`


`export function previewMatchSortingFn(item: Match, header: string): string | number {
switch (header) {
case 'home':
return item.homeTeam.name;
case 'away':
return item.awayTeam.name;
case 'date':
if (item.dateTime) {
// this will return the number representation of the date
return item.dateTime.valueOf();
}
return;
default:
break;
}
}`

我花了几个小时研究这个问题。

  1. 作为 @ avern 提到,您需要导入 MatSortModule
  2. 确保你是 没有封闭的表在一个 *ngIf。改为 [hidden]@ zerg 推荐。(我不明白为什么)

希望这个能帮上忙。

我有两个问题。

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

    NgAfterViewInit (){ Sort = this. sort; }

我发现了一个旧博客,它帮助我开始工作: 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

MatSort 可能无法工作的原因之一是在定义之前将其添加到 dataSource (即 this.dataSource.sort = this.sort)。这可能有多种原因:

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

  2. 当您在表元素上使用 * ngIf 时,如果它是父元素,那么它就是模板之一,并且这个 * ngIf 会导致在您尝试设置 MatSort 时表不会呈现。例如,如果您的表元素上有 *ngIf="dataSource.data.length > 0"(只有当存在数据时才呈现它) ,并且在使用数据设置 this.dataSource.data之后立即设置了 this.dataSource.sort = this.sort。组件视图尚未重新呈现,因此仍然没有定义 MatSort。

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

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

而不是写:

@ViewChild(MatSort) sort: MatSort;

使用一个用于 matSort 的 setter。一旦视图中的 matSort 发生变化(即第一次定义) ,这个 setter 就会触发,当你点击箭头改变排序时,它就不会触发。这看起来像这样:

@ViewChild(MatSort) set matSort(sort: MatSort) {
this.dataSource.sort = sort;
}

如果您有其他的函数(以编程方式)改变排序,我不确定它是否会再次触发,我还没有测试过这个。如果不想确保只在排序未定义的情况下设置排序,可以这样做:

@ViewChild(MatSort) set matSort(sort: MatSort) {
if (!this.dataSource.sort) {
this.dataSource.sort = sort;
}
}

实际上,matColumnDef 名称(即列名称)和 Class/Interface 属性名称应该相等才能正常工作。

有时我们不能更改 Class/Interface 属性名,在这种情况下,我们可以实现如下自定义排序。

let say your columns  as  ['id', 'name'] and
your class/interface  as  ['userId', 'name']

如果我们对 身份证列执行排序,它就不会工作。 尝试使用自定义排序

this.dataSource.sortingDataAccessor = (item,property)=>{


// where item is your class/interface data
// where property is your column name


switch(property){
case 'id' : return item.userId
default: return item[property];
}
}

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

这将工作(属性的名称与列 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']

这将不起作用(属性的名称与列 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']

顺便说一句,这也不起作用(一个属性的长度) :

<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']

这个也是:

<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']

如果你读完所有的答案都没用,也许你和我有同样的问题。

问题是我的 MatTableDataSource对象

dataSource = new MatTableDataSource<StbElement>(ELEMENT_DATA);

在没有 this的 html 文件中使用。

改变:

<table mat-table [dataSource]="dataSource" matSort class="mat-elevation-z8">

致:

<table mat-table [dataSource]="this.dataSource" matSort class="mat-elevation-z8">

解决了问题。

我找到了这个问题的多个答案,但是单独实现它们并没有给我任何结果。所以我尝试合并答案,结果奏效了。

首先,我在 NgAfterViewInit 接口中添加了 ViewChild 排序

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

对于第二步,我将容器内的 * ngIf 更改为[ hide ]。我确实得到一个错误,说明该值没有加载。但到目前为止,这还不是一个值得关注的主要问题。

之前

<div class="mat-elevation-z0 container-fluid" *ngIf={some boolean resultant condition}>

之后

<div class="mat-elevation-z0 container-fluid" [hidden] = {negation of your boolean expression}>

嘘..。 还可以考虑在加载表时添加加载微调器 垫脚至上述 b 以上。

    <ng-container matColumnDef="loading">
<mat-footer-cell *matFooterCellDef colspan=6>
<div class="uploader-status">
<mat-spinner strokeWidth="25" [diameter]="100" title="Server Starting" ></mat-spinner>
</div>
</mat-footer-cell>
</ng-container>




<mat-footer-row *matFooterRowDef="['loading']" [ngStyle]="{'display': (this.candidateService.candidateRecords!=null) ? 'none':'block'}"></mat-footer-row>
My solution for this problem is as below -




1. These two lines will go in the same order.


this.dataSource = new MatTableDataSource(myRowDataArray);// this dataSource is used in table tag.
this.dataSource.sort = this.sort;




2. Pass MatTableDataSource object in [dataSource]
<table mat-table [dataSource]="dataSource">
// rest of the table definition here
</table>


3. By default, the MatTableDataSource sorts with the assumption that the sorted column's name matches the data property name that the column displays.


Example -
<ng-container matColumnDef="date" >
<th class="headers" mat-header-cell  *matHeaderCellDef mat-sort-header>Date</th>
<td class="data" mat-cell *matCellDef="let row">\{\{row.date|date}}</td>
</ng-container>


4. If the table is inside *ngIf,then replace it with [hidden] or some other filter.

我错过了第二点。

Cheers!

除了前面的所有答案之外,有时在数据检索时表不可见。例如,我必须在一个模式/对话框中显示一个包含 MatSort 和 MatPaginator 的表。因此,我必须通过它们各自的输出发射器函数传入元素,如下所示:

<... matSort #sort="matSort" (matSortChange)="sortData(sort)">
<... #paginator (page)="changePaginator(paginator)">

还有打字稿:

  @ViewChild(MatSort, { static: false }) set sort(s: MatSort) {
this.dataSource.sort = s;
}
@ViewChild(MatPaginator, { static: false }) set paginator(p: MatPaginator) {
this.dataSource.paginator = p;
}


sortData(sort: MatSort) {
this.sort = sort;
}
changePaginator(paginator: MatPaginator) {
this.paginator = paginator;
}

确保在其输入指令中设置分页程序的默认值,因为上面的代码将在分页之后设置元素,即: [pageSize]="5" [length]="dataSource?.data?.length"。请将此作为以前所有解决方案的最后手段。

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

进口

import { MatSortModule } from '@angular/material/sort';

然后加上

imports: [
...
MatSortModule
],

这个问题主要发生在 sortdataSource之前初始化的时候。在演示中发现 给你dataSource是静态初始化的结果没有问题发生。但是,如果需要异步获取数据,则需要等待来自 API 调用的响应到达并分配给 dataSource,然后才能初始化 sort实例变量。

我不知道原因,但是把 this.dataSource.sort = this.sort;赋值给 ngAfterViewInit()方法没有起作用。即使我证实这个功能是得到打击页面加载后仍然没有工作。 我的解决方案是在 ngOnInit()方法中放置排序分配。

 ngOnInit(): void {
this.service.getAllAudits().subscribe(result => {
this.dataSource  = new MatTableDataSource(result);
this.dataSource.sort = this.sort;
});

}

下面的代码非常适合我,

@ViewChild(MatSort) set matSort(sort: MatSort) {
if (!this.dataSource.sort) {this.dataSource.sort = sort;}}

Mat-sort & mat-paginator 无法工作的主要原因是

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

改变

@ViewChild('matsort') sort: MatSort;

@ViewChild(matSort) sort: MatSort

为我做的一定是一样的

<table mat-table [dataSource]="dataSource" class="mat-elevation-z8" matSort matSortActive="name" matSortDirection="asc">

在花了几个星期的时间之后,我发现你是这样的

  1. 您需要在 app.module.ts 中导入 MatSortModule。
 imports: [
...
MatSortModule
],
<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
  1. 在 ngViewInit 中定义 sort 和 paginator
ngAfterViewInit(): void {
this.dataSource.sort = this.sort;
this.dataSource.paginator = this.paginator;
this.dataSource.paginator?._changePageSize(400)
}

它为我工作. 。

@ViewChild('sortConfigTable', { static: false }) sortConfigTable: MatSort;

数据初始分配后

      this.dataSource.data = ds;


setTimeout(() => {
if (this.sortConfigTable) {
this.dataSource.sort = this.sortConfigTable;
}
}, 1000);

在分配 dataSource.sort = this. sort 时,应该将该行保留在 ngAfterViewInit 内部,而不是 ngOnInit 内部。

我也有同样的问题,一旦我做到了以上,它就开始正常工作了。