I have encountered an issue with my two MatTables in separate components, each using data sources from different observables. One of the tables has a functioning sort feature, but the other seems to have a problem with the @ViewChild for MatSort not initializing during ngOnInit.
Even though the data renders and the table displays sort buttons, the sorting functionality is not working properly. I have checked my imports, module, and everything seems to be correct.
When logging the MatSort object, one component shows a valid MatSort object while the other shows it as undefined.
The sorting feature is not functioning correctly.
Code snippet from 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;
}
In contrast, the next component initializes in a similar way, but the @ViewChild for MatSort shows up as a valid MatSort Object.
Code snippet from 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)
})
Code snippet from message.service:
getUserSent() {
let messages:any[] = [];
this.userSent = this.afs
.collection('messages', ref => ref.where('uid', '==', `${this.currentUser.uid}`)).snapshotChanges()
return this.userSent
}
Code snippet from 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>
I am struggling to understand why the sort property returns undefined in my first component while in the second working component it returns a proper object. Could someone shed light on whether there may be something related to the order of @ViewChild declaration?