我正在使用来自不同可观察对象的数据源在不同组件中运行两个MatTable。我的表排序功能之一工作正常,但是在第二个表上,好像MatView的@ViewChild在ngOnInit期间未初始化。
数据渲染,并且材质表具有排序按钮,但功能不存在。检查了我的导入和模块,一切都很好。
记录MatSort时,一个组件会记录MatSort对象,而另一个则未定义
排序不起作用。
Feed.component:
import { PostService } from './../../services/post.service';
import { Post } from './../../models/post';
import { Component, OnInit, ViewChild, ChangeDetectorRef} from
'@angular/core';
import { MatSort, MatTableDataSource, MatCheckbox, MatPaginator,
MatTabChangeEvent, MatDialog, MatDialogActions, MatTable} from
"@angular/material"
export class FeedComponent implements OnInit {
@ViewChild(MatSort) sort: MatSort;
@ViewChild(MatPaginator) paginator: MatPaginator;
postData: Post[] =[];
dataSource : MatTableDataSource<any>
currentUser = JSON.parse(localStorage.getItem('user'))
displayedColumns:string[] = ['User','Title', "Description",
"Contact" ]
posts = this.ps.getPosts();
constructor(private ps: PostService, public dialog:MatDialog,
public change:ChangeDetectorRef, public ms:MessageService) {
}
refreshPosts(){
console.log(this.sort) < -------comes back undefined
this.posts.subscribe(posts=>{
this.dataSource.sort = this.sort
this.postData = posts.filter(post => post.uid !=
`${this.currentUser.uid}` && post.claimedBy
!=`${this.currentUser.uid}`);
this.dataSource= new MatTableDataSource(this.postData)
this.dataSource.paginator = this.paginator;
});
}
ngOnInit() {
this.refreshPosts()
console.log(this.sort)
}
Post.service
getPosts(){
return this.afs.collection('posts').snapshotChanges()
.pipe(map(actions =>
actions.map(this.documentToDomainObject)))
}
documentToDomainObject = _ => {
const object = _.payload.doc.data();
object.id = _.payload.doc.id;
return object;
}
现在我的下一个组件以相同的方式初始化,但是@ViewChild显示为MatSort对象
Message.component:
export class MessageComponent implements OnInit {
@ViewChild(MatSort) sort: MatSort;
userReceived: MatTableDataSource<any>;
userSent: MatTableDataSource<any>;
displayedColumns:string[] = ["createdAt",'author',"title", "Delete"]
sentColumns:string[] = ["createdAt","recipient", "title", "Delete"]
currentUserId= this.currentUser['uid']
currentUsername = this.currentUser['displayName']
recipient:any;
selectedMessage: MatTableDataSource<Message>;
messageColumns= ['From','Title',"Body"];
constructor(public ms:MessageService, public change:ChangeDetectorRef, public dialog: MatDialog ) { }
ngOnInit() {
console.log(this.sort)
this.updateMessages()
this.currentUserId = this.currentUserId;
this.currentUsername = this.currentUsername;
}
updateMessages(){
this.ms.getUserSent().subscribe(messages => {
console.log(this.sort) <------logs MatSort object
this.userSent = new MatTableDataSource(messages)
this.userSent.sort = this.sort
console.log(this.userSent.sort)
console.log(this.userSent.data)
})
message.service
getUserSent() {
let messages:any[] = [];
this.userSent = this.afs
.collection('messages', ref => ref.where('uid', '==', `${this.currentUser.uid}`)).snapshotChanges()
return this.userSent
}
feed.component.html
<div class = "mat-elevation-z8">
<mat-form-field>
<input matInput (keyup)="applyFilter($event.target.value)" placeholder="Search Posts">
</mat-form-field>
<table matSort mat-table [dataSource]="dataSource" style="text-align:left">
<ng-container matColumnDef="User">
<th mat-header-cell *matHeaderCellDef mat-sort-header>User</th>
<td mat-cell *matCellDef="let post">{{post.displayName}}</td>
</ng-container>
<ng-container matColumnDef="Title">
<th mat-header-cell *matHeaderCellDef>Title</th>
<td mat-cell *matCellDef="let post">{{post.title | truncate:15:false }}</td>
</ng-container>
<ng-container matColumnDef="Description">
<th mat-header-cell *matHeaderCellDef >Description</th>
<td mat-cell *matCellDef="let post">{{post.description | truncate: 20 : false}}</td>
</ng-container>
<ng-container matColumnDef="Contact">
<th mat-header-cell *matHeaderCellDef> Contact </th>
<td mat-cell *matCellDef="let post">
<button id="{{post.id}}" color="primary" (click)="openDialog($event.target.id)" style = "outline:none" value={{post.id}}>Claim</button>
</td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
<tr mat-row *matRowDef='let row; columns: displayedColumns'></tr>
</table>
</div>
<mat-paginator [length]="this.postData.length" [pageSize]="5" [pageSizeOptions]="[5,10,25]"></mat-paginator>
我真的找不到为什么在我的第二个工作组件中,排序返回并定义对象时,排序返回未定义的原因。我是否缺少有关@ViewChild的顺序的信息?
答案 0 :(得分:3)
摘自官方文档:https://angular.io/api/core/ViewChild#description
视图查询是在调用ngAfterViewInit回调之前设置的。
为了启动@ViewChild
属性,您需要在ngAfterViewInit
生命周期挂钩中调用它。
export class MessageComponent implements OnInit, AfterViewInit {
@ViewChild(MatSort) sort: MatSort;
ngAfterViewInit(){
console.log(this.sort)
}
}
如果您使用的是Angular 8,则由于需要@ViewChild
标志,因此需要重构static
属性的实现
答案 1 :(得分:0)
FeedComponent
中的问题是您要在初始化this.dataSource.sort = this.sort
之前进行this.dataSource
分配
refreshPosts(){
console.log(this.sort) < -------comes back undefined
this.posts.subscribe(posts=>{
this.postData = posts.filter(post => post.uid != `${this.currentUser.uid}` && post.claimedBy !=`${this.currentUser.uid}`);
this.dataSource= new MatTableDataSource(this.postData)
this.dataSource.sort = this.sort // make assignment after initializing this.dataSource
this.dataSource.paginator = this.paginator;
});
}
请注意,console.log(this.sort)
仍然会由于生命周期顺序而无法打印。 ngOnInit
上的视图查询未设置。
因此出现了问题;那么this.dataSource.sort = this.sort
分配在ngOnInit
中的MessageComponent
中如何工作?
答案很长,但可以简单地说。因为该代码在subscribe
回调中执行。由于在发出observable时将执行订阅回调中的代码,因此会发生异步操作。 ,并且异步操作会在执行ngAfterViewInit
挂钩的周期之后的后续更改检测周期中发生。
您不会在第二个组件中得到未定义的输出,因为该console.log语句也在订阅回调中执行。将该日志语句移出订阅回调也将打印未定义。
如果将console.log语句放在ngAfterViewInit
挂钩中,则无论是否将它们放置在订阅回调中,它们都将打印实际值。
作为摘要;
初始化this.datasource
this.dataSource= new MatTableDataSource(this.postData)
this.dataSource.sort = this.sort // make assignment after initializing
并在ngAfterViewInit
钩子中执行此操作,即使由于异步操作而在ngOnInit
中也可以运行。