mat-sort 不适用于 mat-table
mat-sort not working on mat-table
我的 mat-table 工作正常,但是当按照官方 api 文档添加 mat-sort 时,它在 ngAfterViewInit 失败并显示以下消息
Cannot set property 'sort' of undefined
at ViewFeedbackComponent.ngAfterViewInit
关于这个问题已经有一个 SO post(见下文 link) 但我仍然无法让它工作。
有人发现问题了吗?官方示例使用组件本身定义的 "static" MatTableDataSource,但是我从后端查询。
非常感谢任何帮助!
MatSortModule 已经在 app.module.ts 中导入,mat-sort-header 指令应用于列并且 ngAfterViewInit 已经与官方示例中的完全一样...
import { Component, OnInit, ViewEncapsulation, ViewChild, AfterViewInit} from '@angular/core';
import { Feedback} from '../../../../../models/feedback';
import { FeedbackService} from '../../services/feedback.service';
import { MatTableDataSource, MatSort} from '@angular/material';
@Component({
selector: 'app-view-feedback',
templateUrl: './view-feedback.component.html',
styleUrls: ['./view-feedback.component.css'],
encapsulation: ViewEncapsulation.Emulated
})
export class ViewFeedbackComponent implements OnInit, AfterViewInit {
feedbacks: Feedback[] = [];
showSpinner: boolean = true;
displayedColumns: String[] = [
'id',
'user',
'timestamp',
'stars'
];
dataSource: MatTableDataSource < Feedback > ;
@ViewChild(MatSort) sort: MatSort;
constructor(private _feedbackService: FeedbackService) {}
ngOnInit() {
this._feedbackService.getFeedback.subscribe(
res => {
this.feedbacks = res;
this.dataSource = new MatTableDataSource(this.feedbacks);
}
);
}
ngAfterViewInit() {
this.dataSource.sort = this.sort;
}
}
<div class="mat-tbl-container mat-elevation-z8">
<mat-table #tbl [dataSource]="dataSource" matSort>
<!-- column definitions -->
<ng-container matColumnDef="id">
<mat-header-cell *matHeaderCellDef mat-sort-header>Id</mat-header-cell>
<mat-cell *matCellDef="let r"> {{r._id}} </mat-cell>
</ng-container>
<ng-container matColumnDef="user">
<mat-header-cell *matHeaderCellDef mat-sort-header>User Id</mat-header-cell>
<mat-cell *matCellDef="let r"> {{r.user}} </mat-cell>
</ng-container>
<ng-container matColumnDef="timestamp">
<mat-header-cell *matHeaderCellDef mat-sort-header>Date</mat-header-cell>
<mat-cell *matCellDef="let r"> {{r.timestamp}} </mat-cell>
</ng-container>
<ng-container matColumnDef="stars">
<mat-header-cell *matHeaderCellDef mat-sort-header>Stars</mat-header-cell>
<mat-cell *matCellDef="let r"> {{r.stars}} </mat-cell>
</ng-container>
<!-- tbl display settings -->
<mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
<mat-row *matRowDef="let row; columns: displayedColumns;"></mat-row>
</mat-table>
问题是下一段代码
ngAfterViewInit() {
this.dataSource.sort = this.sort;
}
发生在您实际获得 table 订阅之前:
ngOnInit() {
this._feedbackService.getFeedback.subscribe(
res => {
this.feedbacks = res;
this.dataSource = new MatTableDataSource(this.feedbacks);
}
);
}
作为一种可能的解决方案,您可以通过 Observable.zip
同步 ngAfterViewInit
调用和 getFeedback
订阅。请参考RxJS zip documentation
我正在使用旧版本 angular-material 中的前一个排序方法示例。最新的 angular-material 排序示例使用 ngAfterViewInit()
调用排序 this.dataSource.sort = this.sort;
我无法使用新示例进行排序。旧的排序方法使用 extends DataSource 。我能够使用新路径 `import { DataSource } from '@angular/cdk/table';
导入 DataSource
import { Component, ViewChild, Inject, OnInit, ElementRef } from '@angular/core';
import { MatTableDataSource, MatSort } from '@angular/material';
import { DataSource } from '@angular/cdk/table';
import { Observable } from 'rxjs/Observable';
import { HttpClient, HttpResponse, HttpHeaders, HttpRequest} from '@angular/common/http';
import 'rxjs/add/operator/startWith';
import 'rxjs/add/observable/merge';
import 'rxjs/add/observable/of';
import 'rxjs/add/operator/map';
export interface Data {}
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit {
myData: Array < any > ;
displayedColumns = ['id', 'name'];
dataSource: MyDataSource;
@ViewChild(MatSort) sort: MatSort;
constructor(private http: HttpClient) {}
getData() {
let url = 'https://api.mydatafeeds.com/v1.1/cumulative_player_data.json?';
let headers = new HttpHeaders({ "Authorization": "123ykiki456789123456" });
this.http.get(url, {headers})
.subscribe(res => {
this.myData = res;
this.dataSource = new MyDataSource(this.myData, this.sort);
});
}
ngOnInit() {
this.getData();
}
}
export class MyDataSource extends DataSource < any > {
constructor(private dataBase: Data[], private sort: MatSort) {
super();
}
/** Connect function called by the table to retrieve one stream containing the data to render. */
connect(): Observable < Data[] > {
const displayDataChanges = [
Observable.of(this.dataBase),
this.sort.sortChange,
];
return Observable.merge(...displayDataChanges).map(() => {
return this.getSortedData();
});
}
disconnect() {}
/** Returns a sorted copy of the database data. */
getSortedData(): Data[] {
const data = this.dataBase.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 'id':
[propertyA, propertyB] = [a.id, b.id];
break;
case 'name':
[propertyA, propertyB] = [a.name, b.name];
break;
}
let valueA = isNaN(+propertyA) ? propertyA : +propertyA;
let valueB = isNaN(+propertyB) ? propertyB : +propertyB;
return (valueA < valueB ? -1 : 1) * (this.sort.direction == 'asc' ? 1 : -1);
});
}
}
<mat-table #table [dataSource]="dataSource" matSort>
<ng-container matColumnDef="id">
<mat-header-cell *matHeaderCellDef mat-sort-header> Id </mat-header-cell>
<mat-cell *matCellDef="let data"> <b>{{data.id}}.</b>
</mat-cell>
</ng-container>
<ng-container matColumnDef="name">
<mat-header-cell *matHeaderCellDef mat-sort-header> Id </mat-header-cell>
<mat-cell *matCellDef="let data"> <b>{{data.name}}.</b>
</mat-cell>
</ng-container>
<mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
<mat-row *matRowDef="let data; columns: displayedColumns;"></mat-row>
</mat-table>
我重新定义了继承自 MatTableDataSource 的连接方法坏主意...
在 angular 7 中,对两个分页器使用以下示例,但将分页器替换为排序。
https://stackblitz.com/edit/data-table-multiple-data-source
这里是这个问题的副本:
对此的简单解决方案不是在 ngAfterViewInit 中声明排序,而是在从 "this._feedbackService.getFeedback.subscribe" 获得结果后声明。
解决方法如下
ngOnInit() {
this._feedbackService.getFeedback.subscribe(
res => {
this.feedbacks = res;
this.dataSource = new MatTableDataSource(this.feedbacks);
this.dataSource.sort = this.sort; //this will solve your problem
}
);
}
上面那个对我来说很合适。
谢谢,
确保在从 API
获取数据时添加了 {static: false}
@ViewChild(MatSort, {static: false}) sort: MatSort;
要使 matSort 正常工作,类型定义很重要,至少我是这么认为的。所以在代码中使用 type as any :
数据源:MatTableDataSource;不起作用。必须在此处定义一个类型才能使其工作,尝试定义一个接口并将其传递到 MatTableDataSource 的泛型中。此外,matColumnDef 必须匹配定义类型的 属性 名称。
不需要重新初始化对象,只需要更改数据即可
ngOnInit() {
this._feedbackService.getFeedback.subscribe(
res => {
this.feedbacks = res;
// this.dataSource = new MatTableDataSource(this.feedbacks);
// this.dataSource.sort = this.sort; //this will solve your problem
// becomes
this.dataSource.data = this.feedbacks
}
);
}
我的 mat-table 工作正常,但是当按照官方 api 文档添加 mat-sort 时,它在 ngAfterViewInit 失败并显示以下消息
Cannot set property 'sort' of undefined at ViewFeedbackComponent.ngAfterViewInit
关于这个问题已经有一个 SO post(见下文 link)
有人发现问题了吗?官方示例使用组件本身定义的 "static" MatTableDataSource,但是我从后端查询。
非常感谢任何帮助!
MatSortModule 已经在 app.module.ts 中导入,mat-sort-header 指令应用于列并且 ngAfterViewInit 已经与官方示例中的完全一样...
import { Component, OnInit, ViewEncapsulation, ViewChild, AfterViewInit} from '@angular/core';
import { Feedback} from '../../../../../models/feedback';
import { FeedbackService} from '../../services/feedback.service';
import { MatTableDataSource, MatSort} from '@angular/material';
@Component({
selector: 'app-view-feedback',
templateUrl: './view-feedback.component.html',
styleUrls: ['./view-feedback.component.css'],
encapsulation: ViewEncapsulation.Emulated
})
export class ViewFeedbackComponent implements OnInit, AfterViewInit {
feedbacks: Feedback[] = [];
showSpinner: boolean = true;
displayedColumns: String[] = [
'id',
'user',
'timestamp',
'stars'
];
dataSource: MatTableDataSource < Feedback > ;
@ViewChild(MatSort) sort: MatSort;
constructor(private _feedbackService: FeedbackService) {}
ngOnInit() {
this._feedbackService.getFeedback.subscribe(
res => {
this.feedbacks = res;
this.dataSource = new MatTableDataSource(this.feedbacks);
}
);
}
ngAfterViewInit() {
this.dataSource.sort = this.sort;
}
}
<div class="mat-tbl-container mat-elevation-z8">
<mat-table #tbl [dataSource]="dataSource" matSort>
<!-- column definitions -->
<ng-container matColumnDef="id">
<mat-header-cell *matHeaderCellDef mat-sort-header>Id</mat-header-cell>
<mat-cell *matCellDef="let r"> {{r._id}} </mat-cell>
</ng-container>
<ng-container matColumnDef="user">
<mat-header-cell *matHeaderCellDef mat-sort-header>User Id</mat-header-cell>
<mat-cell *matCellDef="let r"> {{r.user}} </mat-cell>
</ng-container>
<ng-container matColumnDef="timestamp">
<mat-header-cell *matHeaderCellDef mat-sort-header>Date</mat-header-cell>
<mat-cell *matCellDef="let r"> {{r.timestamp}} </mat-cell>
</ng-container>
<ng-container matColumnDef="stars">
<mat-header-cell *matHeaderCellDef mat-sort-header>Stars</mat-header-cell>
<mat-cell *matCellDef="let r"> {{r.stars}} </mat-cell>
</ng-container>
<!-- tbl display settings -->
<mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
<mat-row *matRowDef="let row; columns: displayedColumns;"></mat-row>
</mat-table>
问题是下一段代码
ngAfterViewInit() {
this.dataSource.sort = this.sort;
}
发生在您实际获得 table 订阅之前:
ngOnInit() {
this._feedbackService.getFeedback.subscribe(
res => {
this.feedbacks = res;
this.dataSource = new MatTableDataSource(this.feedbacks);
}
);
}
作为一种可能的解决方案,您可以通过 Observable.zip
同步 ngAfterViewInit
调用和 getFeedback
订阅。请参考RxJS zip documentation
我正在使用旧版本 angular-material 中的前一个排序方法示例。最新的 angular-material 排序示例使用 ngAfterViewInit()
调用排序 this.dataSource.sort = this.sort;
我无法使用新示例进行排序。旧的排序方法使用 extends DataSource 。我能够使用新路径 `import { DataSource } from '@angular/cdk/table';
import { Component, ViewChild, Inject, OnInit, ElementRef } from '@angular/core';
import { MatTableDataSource, MatSort } from '@angular/material';
import { DataSource } from '@angular/cdk/table';
import { Observable } from 'rxjs/Observable';
import { HttpClient, HttpResponse, HttpHeaders, HttpRequest} from '@angular/common/http';
import 'rxjs/add/operator/startWith';
import 'rxjs/add/observable/merge';
import 'rxjs/add/observable/of';
import 'rxjs/add/operator/map';
export interface Data {}
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit {
myData: Array < any > ;
displayedColumns = ['id', 'name'];
dataSource: MyDataSource;
@ViewChild(MatSort) sort: MatSort;
constructor(private http: HttpClient) {}
getData() {
let url = 'https://api.mydatafeeds.com/v1.1/cumulative_player_data.json?';
let headers = new HttpHeaders({ "Authorization": "123ykiki456789123456" });
this.http.get(url, {headers})
.subscribe(res => {
this.myData = res;
this.dataSource = new MyDataSource(this.myData, this.sort);
});
}
ngOnInit() {
this.getData();
}
}
export class MyDataSource extends DataSource < any > {
constructor(private dataBase: Data[], private sort: MatSort) {
super();
}
/** Connect function called by the table to retrieve one stream containing the data to render. */
connect(): Observable < Data[] > {
const displayDataChanges = [
Observable.of(this.dataBase),
this.sort.sortChange,
];
return Observable.merge(...displayDataChanges).map(() => {
return this.getSortedData();
});
}
disconnect() {}
/** Returns a sorted copy of the database data. */
getSortedData(): Data[] {
const data = this.dataBase.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 'id':
[propertyA, propertyB] = [a.id, b.id];
break;
case 'name':
[propertyA, propertyB] = [a.name, b.name];
break;
}
let valueA = isNaN(+propertyA) ? propertyA : +propertyA;
let valueB = isNaN(+propertyB) ? propertyB : +propertyB;
return (valueA < valueB ? -1 : 1) * (this.sort.direction == 'asc' ? 1 : -1);
});
}
}
<mat-table #table [dataSource]="dataSource" matSort>
<ng-container matColumnDef="id">
<mat-header-cell *matHeaderCellDef mat-sort-header> Id </mat-header-cell>
<mat-cell *matCellDef="let data"> <b>{{data.id}}.</b>
</mat-cell>
</ng-container>
<ng-container matColumnDef="name">
<mat-header-cell *matHeaderCellDef mat-sort-header> Id </mat-header-cell>
<mat-cell *matCellDef="let data"> <b>{{data.name}}.</b>
</mat-cell>
</ng-container>
<mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
<mat-row *matRowDef="let data; columns: displayedColumns;"></mat-row>
</mat-table>
我重新定义了继承自 MatTableDataSource 的连接方法坏主意...
在 angular 7 中,对两个分页器使用以下示例,但将分页器替换为排序。
https://stackblitz.com/edit/data-table-multiple-data-source
这里是这个问题的副本:
对此的简单解决方案不是在 ngAfterViewInit 中声明排序,而是在从 "this._feedbackService.getFeedback.subscribe" 获得结果后声明。
解决方法如下
ngOnInit() {
this._feedbackService.getFeedback.subscribe(
res => {
this.feedbacks = res;
this.dataSource = new MatTableDataSource(this.feedbacks);
this.dataSource.sort = this.sort; //this will solve your problem
}
);
}
上面那个对我来说很合适。
谢谢,
确保在从 API
获取数据时添加了{static: false}
@ViewChild(MatSort, {static: false}) sort: MatSort;
要使 matSort 正常工作,类型定义很重要,至少我是这么认为的。所以在代码中使用 type as any : 数据源:MatTableDataSource;不起作用。必须在此处定义一个类型才能使其工作,尝试定义一个接口并将其传递到 MatTableDataSource 的泛型中。此外,matColumnDef 必须匹配定义类型的 属性 名称。
不需要重新初始化对象,只需要更改数据即可
ngOnInit() {
this._feedbackService.getFeedback.subscribe(
res => {
this.feedbacks = res;
// this.dataSource = new MatTableDataSource(this.feedbacks);
// this.dataSource.sort = this.sort; //this will solve your problem
// becomes
this.dataSource.data = this.feedbacks
}
);
}