mat-sort-header not showing up - angular-material

I'm trying to use angular material data table with angular 6 but I don't get sorting headers to show up. I don't get any errors and nothing is showing up at all.
<mat-card>
<mat-card-content>
<div class="example-container mat-elevation-z8">
<mat-table #table [dataSource]="dataSource" matSort>
<!-- Position Column -->
<ng-container matColumnDef="StartDate">
<mat-header-cell *matHeaderCellDef mat-sort-header> Datum </mat-header-cell>
<mat-cell *matCellDef="let row"> {{row.StartDate}} </mat-cell>
</ng-container>
<ng-container matColumnDef="StartTime">
<mat-header-cell *matHeaderCellDef mat-sort-header> Uhrzeit </mat-header-cell>
<mat-cell *matCellDef="let row"> {{row.StartTime}} </mat-cell>
</ng-container>
<ng-container matColumnDef="customer.CustomerShort">
<mat-header-cell *matHeaderCellDef> Kunde </mat-header-cell>
<mat-cell *matCellDef="let row"> {{row.customer.CustomerShort}} </mat-cell>
</ng-container>
test-drive-list-component.html
I have imported MatSort module and linked MatSort.
export class TestDriveListComponent implements OnInit {
displayedColumns = ['StartDate', 'StartTime', 'customer.CustomerShort',
'user.UserShort',
'automobile.AutomobileShort', 'automobile.licenseNumber', 'status',
'actions'];
testdrives: TestDrive[];
dataSource: TestdriveDataSource | null;
query = '';
#ViewChild(MatPaginator) paginator: MatPaginator;
#ViewChild(MatSort) sort: MatSort;
constructor(private dataService: DataService, public dialog: MatDialog) { }
ngOnInit() {
this.dataSource = new TestdriveDataSource(this.dataService, this.sort);
}
applyFilter() {
this.dataSource.filter = this.query;
}
I am not very experienced with angular and any help would be appreciated.

Dear #Florian Glaesser,
Please try below steps once:
1. try to import MatSortModule in your app.module.ts
2. Next we need to define matsort local variable as below:
#ViewChild(MatSort) matSort: MatSort;
private sort: any;
#ViewChild(MatSort) set content(content: ElementRef) {
this.sort = content;
if (this.sort) {
this.dataSource.sort = this.sort;
}
3. once you got your data in the ngOnit, bind the matSort as below:
ngOnInit() {
this.dataSource = new MatTableDataSource(<your service which returns the data>);
this.dataSource.sort = this.matSort;
}
This worked for me. Please try it once.

Related

MatSort and MatPaginator not being initialized using #ViewChild and ngAfterViewInit if inside *ngIf

I am using a mat table with paginator and sort within an *ngIf. The table data is retrieved using an API.
This is the component's typescript code:
export class UserPermissionAdminComponent implements AfterViewInit, OnInit {
dataSource: MatTableDataSource<UserPermission> = new MatTableDataSource<UserPermission>();
columnsToDisplay: string[] = ['id', 'name'];
#ViewChild(MatSort, { static: false }) sort!: MatSort;
#ViewChild(MatPaginator, { static: false }) paginator!: MatPaginator;
constructor(private userPermService: UserPermissionService) {
}
ngOnInit(): void {
this.userPermService.getAllUserPermissions()
.subscribe(recvPerms => this.dataSource.data = recvPerms);
}
ngAfterViewInit(): void {
this.dataSource.sort = this.sort;
this.dataSource.paginator = this.paginator;
console.log(this.dataSource.sort);
}
applyFilter(event: Event): void {
const filterValue = (event.target as HTMLInputElement).value;
this.dataSource.filter = filterValue.trim().toLowerCase();
}
}
And this is the component's template:
<div class="container">
<h2>Permisiuni utilizatori</h2>
<ng-container *ngIf="dataSource.data.length; then existingPermissions; else noPermissions">
</ng-container>
<ng-template #existingPermissions>
<div>
<div class="filter-container">
<mat-form-field>
<mat-label>Cautare</mat-label>
<input matInput (keyup)="applyFilter($event)" placeholder="Ex: READ" #input />
</mat-form-field>
</div>
<div class="table-container mat-elevation-z8">
<table mat-table [dataSource]="dataSource" matSort>
<ng-container matColumnDef="id">
<th mat-header-cell *matHeaderCellDef mat-sort-header> ID </th>
<td mat-cell *matCellDef="let permission"> {{permission.id}} </td>
</ng-container>
<ng-container matColumnDef="name">
<th mat-header-cell *matHeaderCellDef mat-sort-header> Denumire permisiune </th>
<td mat-cell *matCellDef="let permission"> {{permission.name}} </td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="columnsToDisplay"></tr>
<tr mat-row *matRowDef="let rowData; columns: columnsToDisplay"></tr>
</table>
<mat-paginator [pageSizeOptions]="[5, 10, 20]"></mat-paginator>
</div>
</div>
</ng-template>
<ng-template #noPermissions>
<div>
<span class="notification">Nu a fost gasita nicio permisiune utilizator.</span>
</div>
</ng-template>
</div>
The issue is that sorting and pagination do not work (the console.log also lists that this.sort is undefined). The table contains all the data on a single page. Filtering also works.
I have managed to fix the issue by adding setters to the paginator and sort:
#ViewChild(MatSort, { static: false }) set sort(val: MatSort) {
if (val) {
this.dataSource.sort = val;
}
}
#ViewChild(MatPaginator, { static: false }) set paginator(val: MatPaginator) {
if (val) {
this.dataSource.paginator = val;
}
}
However, the code now works even without ngAfterViewInit. Can someone please explain how and why this works?

Implementing Angular Material Table in my web-app : ERROR : Can't bind to 'mat' since it isn't a known property of 'mat-header-row'

I'm trying to implement an Angular Material Table in my web-app. Unfortunately i've got this error :
"Can't bind to 'mat' since it isn't a known property of 'mat-header-row'"
courses.component.html :
<mat-table [dataSource]="courses" class="mat-elevation-z8">
<ng-container matColumnDef="title">
<mat-header-cell *matHeaderCellDef> Title</mat-header-cell>
<mat-cell *matCellDef="let element"> {{element.title}} </mat-cell>
</ng-container>
<ng-container matColumnDef="description">
<mat-header-cell *matHeaderCellDef> Description</mat-header-cell>
<mat-cell *matCellDef="let element"> {{element.description}}</mat-cell>
</ng-container>
<ng-container matColumnDef="categorie">
<mat-header-cell *matHeaderCellDef> Categorie</mat-header-cell>
<mat-cell *matCellDef="let element"> {{element.categorie}}</mat-cell>
</ng-container>
<ng-container matColumnDef="urlImage">
<mat-header-cell *matHeaderCellDef> Image Url</mat-header-cell>
<mat-cell *matCellDef="let element"> {{element.urlImage}}</mat-cell>
</ng-container>
<ng-container matColumnDef="price">
<mat-header-cell *matHeaderCellDef> Price</mat-header-cell>
<mat-cell *matCellDef="let element"> {{ element.price | currency }}</mat-cell>
</ng-container>
<mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
<mat-row *matRowDef="let row; columns: displayedColumns;"></mat-row>
</mat-table>
courses.component.ts :
import { Component, OnInit } from '#angular/core';
import { CourseService } from 'src/app/modules/courses/services/course.service';
#Component({
selector: 'app-admin-courses',
templateUrl: './admin-courses.component.html',
styleUrls: ['./admin-courses.component.css']
})
export class AdminCoursesComponent implements OnInit {
courses!:any[];
displayedColumns: string[] = ['title', 'description','categorie','urlImage','price'];
constructor(private serviceCourse:CourseService) { }
ngOnInit() {
this.serviceCourse.getAllCourses()
.subscribe(courses=>this.courses=courses)
}
}
file "app.module.ts" of my module "admin" :
import { NgModule } from '#angular/core';
import { AdminCoursesComponent } from './components/admin-courses/admin-courses.component';
import { CommonModule } from '#angular/common';
import { MatTableModule } from '#angular/material/table';
import { CoursesComponent } from '../courses/components/courses/courses.component';
import { AppModuleCourses } from '../courses/app.module';
#NgModule({
declarations: [AdminCoursesComponent],
imports: [
CommonModule,
MatTableModule,
AppModuleCourses,
],
exports:[AdminCoursesComponent],
entryComponents:[CoursesComponent],
providers: [],
bootstrap: [],
})
export class AppModuleAdmin { }
General app file of the app : "app.module.ts" :
import { BrowserModule } from '#angular/platform-browser';
import { NgModule } from '#angular/core';
import { AngularFireModule } from '#angular/fire';
import { AngularFireDatabaseModule } from '#angular/fire/database';
import { AngularFireAuthModule } from '#angular/fire/auth';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { environment } from 'src/environments/environment';
import { BrowserAnimationsModule } from '#angular/platform-browser/animations';
import { MatSliderModule } from '#angular/material/slider';
import { MatCardModule } from '#angular/material/card';
import { FlexLayoutModule } from '#angular/flex-layout';
import { MatButtonModule } from '#angular/material/button';
import { MatMenuModule} from '#angular/material/menu';
import { MatTableModule } from '#angular/material/table';
import { MatSortModule } from '#angular/material/sort';
// import { MatToolbarModule } from '#angular/material/toolbar';
// import { AppModuleAdmin } from './modules/admin/app.module';
import { AppModuleAuth } from './modules/authen/app.module';
import { AppModuleCommun } from './modules/commun/app.module';
import { AppModuleCourses } from './modules/courses/app.module';
import { AppModuleMenu } from './modules/menu/app.module';
import { LoginService } from './modules/authen/services/login.service';
import { AppModuleUsers } from './modules/users/app.module';
import { CourseService } from './modules/courses/services/course.service';
import { CommonModule } from '#angular/common';
#NgModule({
declarations: [
AppComponent,
],
imports: [
BrowserModule,
AppRoutingModule,
AngularFireModule.initializeApp(environment.firebaseConfig, 'project-firebase'),
AngularFireDatabaseModule,
AngularFireAuthModule,
BrowserAnimationsModule,
MatSliderModule,
MatCardModule,
FlexLayoutModule,
MatButtonModule,
MatMenuModule,
MatTableModule,
MatSortModule,
CommonModule,
// MatToolbarModule,
// AppModuleAdmin,
AppModuleAuth,
AppModuleCommun,
AppModuleCourses,
AppModuleMenu,
AppModuleUsers,
],
providers: [LoginService],
bootstrap: [AppComponent]
})
export class AppModule { }
Error message in the console :
NG0303: Can't bind to 'matHeaderRowDef' since it isn't a known property of 'mat-header-row'.
Do I forgot to import a module in my admin-courses.component.ts ? I'm blocked ... Do you have any idea ?
For information, I try to solve using that code in my component.html file but it doesn't solve the problem (still have the same error message) :
<table mat-table [dataSource]="courses" class="mat-elevation-z8">
<ng-container matColumnDef="position">
<th mat-header-cell *matHeaderCellDef> Title </th>
<td mat-cell *matCellDef="let element"> {{element.title}} </td>
</ng-container>
<ng-container matColumnDef="name">
<th mat-header-cell *matHeaderCellDef> Description </th>
<td mat-cell *matCellDef="let element"> {{element.description}} </td>
</ng-container>
<ng-container matColumnDef="weight">
<th mat-header-cell *matHeaderCellDef> Categorie </th>
<td mat-cell *matCellDef="let element"> {{element.categorie}} </td>
</ng-container>
<ng-container matColumnDef="symbol">
<th mat-header-cell *matHeaderCellDef> Image Url </th>
<td mat-cell *matCellDef="let element"> {{element.urlImage}} </td>
</ng-container>
<ng-container matColumnDef="symbol">
<th mat-header-cell *matHeaderCellDef> Price </th>
<td mat-cell *matCellDef="let element"> {{element.price}} </td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
</table>

Angular Material MatPaginator showing page 0 of 0

sorry for the question in advance. I googled my problem before writing this and tried lots of solutions, but without luck.
I'm an Angular noob trying to learn Material.
My simple project makes a http request and uses the JSON received to populate a table.
The Angular Material table is working fine, but the paginator is not.
It is greyed and shows page 0 of 0.
The component.html is as follows:
<div style="height: 80vh;">
<mat-toolbar color="primary">
<mat-toolbar-row>
<button mat-icon-button (click)="sidenav.toggle()" fxShow="true" fxHide.gt-sm>
<mat-icon>menu</mat-icon>
</button>
<span>Teste - Requisição Http/Tabela</span>
<span class="menu-spacer"></span>
</mat-toolbar-row>
</mat-toolbar>
<mat-sidenav-container fxFlexFill>
<mat-sidenav #sidenav>
<mat-nav-list>
<a (click)="sidenav.toggle()" mat-list-item>Fechar</a>
<a href="#" mat-list-item>Link 1</a>
<a href="#" mat-list-item>Link 2</a>
<a href="#" mat-list-item>Link 3</a>
</mat-nav-list>
</mat-sidenav>
<mat-sidenav-content fxFlexFill>
<table mat-table [dataSource]="dataSource" class="mat-elevation-z8">
<ng-container matColumnDef="id">
<th mat-header-cell *matHeaderCellDef> Id </th>
<td mat-cell *matCellDef="let element"> {{element.id}} </td>
</ng-container>
<ng-container matColumnDef="email">
<th mat-header-cell *matHeaderCellDef> Email </th>
<td mat-cell *matCellDef="let element"> {{element.email}} </td>
</ng-container>
<ng-container matColumnDef="first_name">
<th mat-header-cell *matHeaderCellDef> First Name </th>
<td mat-cell *matCellDef="let element"> {{element.first_name}} </td>
</ng-container>
<ng-container matColumnDef="last_name">
<th mat-header-cell *matHeaderCellDef> Last Name </th>
<td mat-cell *matCellDef="let element"> {{element.last_name}} </td>
</ng-container>
<ng-container matColumnDef="avatar">
<th mat-header-cell *matHeaderCellDef> Avatar </th>
<td mat-cell *matCellDef="let element"> {{element.avatar}} </td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
</table>
<mat-paginator [pageSizeOptions]="[5, 10, 25, 100]" showFirstLastButtons></mat-paginator>
</mat-sidenav-content>
</mat-sidenav-container>
</div>
The component.ts is as follows:
import { HttpClient } from '#angular/common/http';
import { AfterViewInit, Component, ViewChild } from '#angular/core';
import { MatPaginator } from '#angular/material/paginator';
import { MatTableDataSource } from '#angular/material/table';
export interface UserData {
id: number;
email: string;
first_name: string;
last_name: string;
avatar: string;
}
const USER_DATA: UserData[] = [];
#Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent implements AfterViewInit {
title = 'Test';
url = 'https://reqres.in/api/users?page=1';
displayedColumns: string[] = ['id', 'email', 'first_name', 'last_name', 'avatar'];
dataSource = new MatTableDataSource<UserData>(USER_DATA);
constructor(private http: HttpClient) {
this.http.get(this.url).toPromise().then(data => {
console.log(data["data"]);
this.dataSource = data["data"]
console.log(this.dataSource)
});
}
#ViewChild(MatPaginator) paginator: MatPaginator;
ngAfterViewInit() {
this.dataSource.paginator = this.paginator;
}
}
What am I doing wrong?
Thanks
Try adding #paginator in
<mat-paginator [pageSizeOptions]="[5, 10, 25, 100]" showFirstLastButtons></mat-paginator>
It should be:
<mat-paginator #paginator [pageSizeOptions]="[5, 10, 25, 100]" showFirstLastButtons></mat-paginator>
Without the id "#paginator" the #ViewChild decorator will never be able to find the element (this id must be the same as the used in the #ViewChild decorator line).
This little detail is not included in the Pagination example in the Angular Material documentation (or I was not able to see it..)
Beside this, try declaring the dataSource object as:
dataSource! = MatTableDataSource<UserData>;
instead of
dataSource = new MatTableDataSource<UserData>(USER_DATA);
Then, when the promise is resolved, assign the contents this way
this.dataSource = new MatTableDataSource<UserData>(data.data);
instead of
this.dataSource = data["data"]
Immediately after that, assign the paginator component to the dataSource.paginator:
this.dataSource.paginator = this.paginator;
Try removing the AfterView and replace the ViewChild with the below code:
#ViewChild(MatPaginator) set matPaginator(paginator: MatPaginator) {
this.dataSource.paginator = paginator;
}
In the angular's documentation, they forgot to add, that you need to define { static: false} or {static: true} .
Like this:
#ViewChild(MatPaginator, {static:false}) paginator: MatPaginator;
in docs:
static - True to resolve query results before change detection runs,
false to resolve after change detection. Defaults to false.
You need to set it to false, if you want to use default.
I needed to add this.paginator.length = +data.meta.total; so that length prop of paginator knew the total possible items, and could calculate the pagination.
Adding, the example from ng docs doesn't show this and docs show as 'hard coded' values.
ng docs need work!

How to show only the data which are not empty in mat-table

How to show only data object which are not empty in response JSON?
<mat-table #table [dataSource]="dataSource">
<ng-container matColumnDef="type">
<mat-header-cell *matHeaderCellDef mat-sort-header> Type </mat-header-cell>
<mat-cell *matCellDef="let element"> {{element.type}} </mat-cell>
</ng-container>
<ng-container matColumnDef="version">
<mat-header-cell *matHeaderCellDef mat-sort-header> Version </mat-header-cell>
<mat-cell *matCellDef="let element"> {{element.version}} </mat-cell>
</ng-container>
<ng-container matColumnDef="number">
<mat-header-cell *matHeaderCellDef mat-sort-header> Number </mat-header-cell>
<mat-cell *matCellDef="let element"> {{element.version}} </mat-cell>
</ng-container>
<ng-container matColumnDef="part">
<mat-header-cell *matHeaderCellDef mat-sort-header> Part </mat-header-cell>
<mat-cell *matCellDef="let element"> {{element.part}} </mat-cell>
</ng-container>
<ng-container matColumnDef="description">
<mat-header-cell *matHeaderCellDef mat-sort-header> Description </mat-header-cell>
<mat-cell *matCellDef="let element"> {{element.description}} </mat-cell>
</ng-container>
<mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
<mat-row *matRowDef="let row; columns: displayedColumns;"></mat-row>
Please find the below sample JSON response and attached the screenshot of the data table.
{"items":[{"description": "Test 12345","part":"P1","type":"AB","version":"V1.0","number":"12345"},{},{},{"description": "Test 67890","part":"P1","type":"XY","version":"V2.1","number":"67890"}]}
Table is rendered correct because you have 2 empty objects in response.
If You want to get rid of them just simply iterate over data array and check if there is empty object.
const yourResponse = [{}, {id: 1}, {}, {id: 2}, {}];
const filteredArray = yourResponse.filter(element => {
if (Object.keys(element).length !== 0) {
return true;
}
return false;
});
// [{id: 1}, {id: 2}]
console.log(filteredArray);
This way you will avoid having empty rows in table.

Data-table don't show my DataSource Array

I have a problem that I do not know how to solve it from my component I send an array of Resource so that another component reads it and injects it into a DataSource that is read by a mat-table. Consulted the documentation of Angular, I see that it is correct. I do not know if it's something in the html that does not allow me to see it. Can someone tell me the reason?
Thank you so much
my .ts
#Input() resources : Resource [];
public dataSource = new MatTableDataSource <Resource> ();
public ngOnInit(): void {
console.log(this.resources)
this.dataSource.data = this.resources
}
my .html
<mat-table class="resources-table" #table [dataSource]="resources" matSort [#animateStagger]="{value:'50'}" fusePerfectScrollbar>
<!-- ID Column -->
<ng-container matColumnDef="_id">
<mat-header-cell *matHeaderCellDef mat-sort-header>ID</mat-header-cell>
<mat-cell *matCellDef="let resource">
<p class="text-truncate">{{resource._id}}</p>
</mat-cell>
</ng-container>
<!-- Name Column -->
<ng-container matColumnDef="name">
<mat-header-cell *matHeaderCellDef mat-sort-header>{{'RESOURCE.NAME' | translate}}</mat-header-cell>
<mat-cell *matCellDef="let resource">
<p class="text-truncate">{{resource.name}}</p>
</mat-cell>
</ng-container>
</mat-table>
console.log(this.resources) is img:
Try to set DataSource property of Mat-Table in which you assinging the data:
HTML code:
\/ <-- Here
<table mat-table [dataSource]="dataSource" matSort class="mat-elevation-z8">
<!-- Position Column -->
<ng-container matColumnDef="_id">
<th mat-header-cell *matHeaderCellDef mat-sort-header> No. </th>
<td mat-cell *matCellDef="let element"> {{element._id}} </td>
</ng-container>
<!-- Name Column -->
<ng-container matColumnDef="name">
<th mat-header-cell *matHeaderCellDef mat-sort-header> Name </th>
<td mat-cell *matCellDef="let element"> {{element.name}} </td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
</table>
TS code:
import { Component, OnInit, ViewChild } from '#angular/core';
import { MatSort, MatTableDataSource } from '#angular/material';
#Component({
selector: 'table-sorting-example',
styleUrls: ['table-sorting-example.css'],
templateUrl: 'table-sorting-example.html',
})
export class TableSortingExample implements OnInit {
displayedColumns: string[] = ['_id', 'name'];
dataSource = new MatTableDataSource([]);
#ViewChild(MatSort) sort: MatSort;
ngOnInit() {
var elements = [{ _id: 1, name: 'Paul Walker' },
{ _id: 2, name: 'Lisa' }];
this.dataSource = new MatTableDataSource(elements); // Set dataSource like this
this.dataSource.sort = this.sort; // and then assign sort
}
}
Stackblitz

Resources