I made an Angular Material Table and now I'm trying to implement Sort. I build the table following the documentation for version 13, but the sorting doesn't work (even though the header is clickable and the sorting arrow changes direction on click.
Here is my component:
import { Component, VERSION, ViewChild } from '#angular/core';
import { MatSort } from '#angular/material/sort';
#Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
})
export class AppComponent {
#ViewChild(MatSort, { static: true }) sort!: MatSort;
dataSource = [
{ value: 'One %value% none', type: 'Type is %type%', time: 1 },
{ value: 'Another %value%', type: 'This type is %type%', time: 3 },
{ value: '%value% none', type: 'The type is %type%', time: 2 },
];
displayedColumns: string[] = Object.keys(this.dataSource[0]);
name = 'Angular ' + VERSION.major;
}
And here is the html:
<p>Table works</p>
<table mat-table matSort [dataSource]="dataSource" class="mat-elevation-z8">
<!-- Value Column -->
<ng-container matColumnDef="value">
<th mat-sort-header mat-header-cell *matHeaderCellDef>Vaule</th>
<td mat-cell *matCellDef="let element">{{ element.value }}</td>
</ng-container>
<!-- Type Column -->
<ng-container matColumnDef="type">
<th mat-sort-header mat-header-cell *matHeaderCellDef>Type</th>
<td mat-cell *matCellDef="let element">{{ element.type }}</td>
</ng-container>
<!-- Time Column -->
<ng-container matColumnDef="time">
<th mat-sort-header mat-header-cell *matHeaderCellDef>Time</th>
<td mat-cell *matCellDef="let element">{{ element.time }}</td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns"></tr>
</table>
The full reproducible example can be found here:
stackblitz
ps: there are a few similar questions in SO, but I couldn't find one with this version and this specifications.
Related
I have this dataSource
In my filtro component, I call to listado-proyectos component and I pass it dataSource
Filtro
<app-listado-proyectos [proyectos]="dataSource" [origen]="'certificados'"
*ngIf="dataSource.length>0"></app-listado-proyectos>
Listado Proyectos
#Component({
selector: 'app-listado-proyectos',
templateUrl: './listado-proyectos.component.html',
styleUrls: ['./listado-proyectos.component.scss']
})
export class ListadoProyectosComponent implements OnInit, OnChanges {
#Input()
proyectos: IProyecto[];
#Input()
origen: string;
dataSource: MatTableDataSource<IProyecto>
columnsToDisplay: string[] = [];
filtro: string;
#ViewChild(MatPaginator, { static: true }) paginator!: MatPaginator;
constructor(private generalService: GeneralService) { }
ngOnChanges(changes: SimpleChanges): void {
this.columnsToDisplay = ['codigo', 'descripcionCorta', 'jefeGrupo', 'responsable',
'estado', 'cliente', 'fechaInicio', 'fechaFin', 'presupuesto', 'facturable',
'certificado'];
this.dataSource = new MatTableDataSource(this.proyectos);
console.log("Listado de proyectos en ListadoProyectosComponent", this.dataSource);
}
<mat-table [dataSource]="dataSource" matTableExporter #exporter="matTableExporter"
multiTemplateDataRows matSort class="mat-elevation-z8">
......
<ng-container matColumnDef="certificado" *ngIf="origen=='certificado'">
<th mat-header-cell *matHeaderCellDef mat-sort-header>Certificado</th>
<td mat-cell *matCellDef="let element">{{element.certificado}} </td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="columnsToDisplay; sticky:true"></tr>
<tr mat-row *matRowDef="let row; columns: columnsToDisplay;"></tr>
</mat-table>
in listado component I get the data
But I get this error
Any idea, please?
Thanks
<mat-table [dataSource]="dataSource" matTableExporter #exporter="matTableExporter" multiTemplateDataRows matSort
class="mat-elevation-z8">
.....
<ng-container matColumnDef="certificado" *ngIf="origen=='certificado'">
<th mat-header-cell *matHeaderCellDef>Certificado</th>
<td mat-cell *matCellDef="let element">{{element.certificado}} </td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="columnsToDisplay; sticky:true"></tr>
<tr mat-row *matRowDef="let row; columns: columnsToDisplay;"></tr>
</mat-table>
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!
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
I am trying to create a mat table with sub columns using Angular Material Table like the link. Is there a way to do this with angular material table? Can I create sub columns from one the columns? Please check the table from the below link
https://datatables.net/examples/basic_init/complex_header.html
Old question, but I had a similar problem and found this example. Angular Material version is 7.3.1. The complete project can be found here
table-basic-example.html
<table mat-table [dataSource]="dataSource" class="mat-elevation-z8">
<!--- Note that these columns can be defined in any order.
The actual rendered columns are set as a property on the row definition" -->
<!-- Position Column -->
<ng-container matColumnDef="position">
<th mat-header-cell *matHeaderCellDef> No. </th>
<td mat-cell *matCellDef="let element"> {{element.position}} </td>
</ng-container>
<!-- Name Column -->
<ng-container matColumnDef="name">
<th mat-header-cell *matHeaderCellDef> Name </th>
<td mat-cell *matCellDef="let element"> {{element.name}} </td>
</ng-container>
<!-- Weight Column -->
<ng-container matColumnDef="weight">
<th mat-header-cell *matHeaderCellDef> Weight </th>
<td mat-cell *matCellDef="let element"> {{element.weight}} </td>
</ng-container>
<!-- Symbol Column -->
<ng-container matColumnDef="symbol">
<th mat-header-cell *matHeaderCellDef> Symbol </th>
<td mat-cell *matCellDef="let element"> {{element.symbol}} </td>
</ng-container>
<!-- Header row first group -->
<ng-container matColumnDef="header-row-first-group">
<th mat-header-cell *matHeaderCellDef
[style.text-align]="center"
[attr.colspan]="2">
First group
</th>
</ng-container>
<!-- Header row second group -->
<ng-container matColumnDef="header-row-second-group">
<th mat-header-cell *matHeaderCellDef [attr.colspan]="2"> Second group </th>
</ng-container>
<tr mat-header-row *matHeaderRowDef="['header-row-first-group', 'header-row-second-group']"></tr>
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
</table>
table-basic-example.ts
import {Component} from '#angular/core';
export interface PeriodicElement {
name: string;
position: number;
weight: number;
symbol: string;
}
const ELEMENT_DATA: PeriodicElement[] = [
{position: 1, name: 'Hydrogen', weight: 1.0079, symbol: 'H'},
{position: 2, name: 'Helium', weight: 4.0026, symbol: 'He'},
{position: 3, name: 'Lithium', weight: 6.941, symbol: 'Li'},
{position: 4, name: 'Beryllium', weight: 9.0122, symbol: 'Be'},
{position: 5, name: 'Boron', weight: 10.811, symbol: 'B'},
{position: 6, name: 'Carbon', weight: 12.0107, symbol: 'C'},
{position: 7, name: 'Nitrogen', weight: 14.0067, symbol: 'N'},
{position: 8, name: 'Oxygen', weight: 15.9994, symbol: 'O'},
{position: 9, name: 'Fluorine', weight: 18.9984, symbol: 'F'},
{position: 10, name: 'Neon', weight: 20.1797, symbol: 'Ne'},
];
/**
* #title Basic use of `<table mat-table>`
*/
#Component({
selector: 'table-basic-example',
styleUrls: ['table-basic-example.css'],
templateUrl: 'table-basic-example.html',
})
export class TableBasicExample {
displayedColumns: string[] = ['position', 'name', 'weight', 'symbol'];
dataSource = ELEMENT_DATA;
}
table-basic-example.css
table {
width: 100%;
}
th.mat-header-cell, td.mat-cell {
text-align: center;
border: 1px solid #CCC;
padding: 0 !important;
}
I wanted a multi-header data table where the 2nd header is in the 2nd row of the data table field but didn't find any solutions related to Angular Material.
2nd header having ‘Area’, ‘City’, ‘State’ will be rendered below 'Address' header, thus using attr.colspan value = 3
Also, <tr mat-header-row *matHeaderRowDef="['stub', ‘area’ , ‘city’, ‘state’]"> is added for 2nd header to work
Here is the solution I have implemented in my code using colspan attribute. Please refer to the comments mentioned in the code
<div class="mat-elevation-z8">
<table mat-table [dataSource]="dataSource">
<ng-container matColumnDef="model">
<th mat-header-cell *matHeaderCellDef class="header-font"> Model</th>
<td mat-cell *matCellDef="let element"> {{element.model}} </td>
</ng-container>
<ng-container matColumnDef="name">
<th mat-header-cell *matHeaderCellDef class="header-font"> Name </th>
<td mat-cell *matCellDef="let element"> {{element.name}} </td>
</ng-container>
<ng-container matColumnDef="address">
<th mat-header-cell [attr.colspan]="3" *matHeaderCellDef class="header-font"> Address </th>
</ng-container>
<!--2nd Header-->
<ng-container matColumnDef="stub">
<th mat-header-cell style="background-color: white; border: none;" [attr.colspan]="2" *matHeaderCellDef> </th>
<!--stub is necessary because 2nd header should not be placed below Model, Name-->
</ng-container>
<ng-container matColumnDef="area">
<th mat-header-cell class="header-font" *matHeaderCellDef> Area </th>
</ng-container>
<ng-container matColumnDef="city">
<th mat-header-cell class="header-font" *matHeaderCellDef> City </th>
</ng-container>
<ng-container matColumnDef="state">
<th mat-header-cell class="header-font" *matHeaderCellDef> State </th>
</ng-container>
<!--add 1 more ng-container for Penetration % field-->
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
<tr mat-header-row *matHeaderRowDef="['stub', ‘area’ , ‘city’, ‘state’]"></tr> <!--Enable this for 2nd Header-->
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
</table>
Here is my angular project configuration,
"#angular/cdk": "^5.2.0",
"#angular/common": "~5.2.6",
"#angular/compiler": "~5.2.6",
"#angular/core": "~5.2.6",
"#angular/forms": "~5.2.6",
"#angular/http": "~5.2.6",
"#angular/material": "^5.2.0"
I am using angular material to build a table of data, I am following the https://material.angular.io/components/table/examples example, the code is almost the same with the exmaple, but the table just doesn't show any thing.
Here is the code:
ts code
export class ordersComponent {
displayedColumns =['position', 'name', 'weight', 'symbol'];
//dataSource = new MatTableDataSource<PeriodicElement>(ELEMENT_DATA);
dataSource = ELEMENT_DATA;
}
export interface PeriodicElement {
name: string;
position: number;
weight: number;
symbol: string;
}
const ELEMENT_DATA : PeriodicElement[]= [
{position: 1, name: 'Hydrogen', weight: 1.0079, symbol: 'H'},
{position: 2, name: 'Helium', weight: 4.0026, symbol: 'He'},
{position: 3, name: 'Li: PeriodicElement[]thium', weight: 6.941, symbol: 'Li'},
{position: 4, name: 'Beryllium', weight: 9.0122, symbol: 'Be'}
];
The html code is
<div class="mat-elevation-z8">
<mat-table mat-table [dataSource]="dataSource">
<ng-container matColumnDef="position">
<th mat-header-cell *matHeaderCellDef> No. </th>
<td mat-cell *matCellDef="let element"> </td>
</ng-container>
<ng-container matColumnDef="name">
<th mat-header-cell *matHeaderCellDef> Name </th>
<td mat-cell *matCellDef="let element"> </td>
</ng-container>
<ng-container matColumnDef="weight">
<th mat-header-cell *matHeaderCellDef> Weight </th>
<td mat-cell *matCellDef="let element"> </td>
</ng-container>
<ng-container matColumnDef="symbol">
<th mat-header-cell *matHeaderCellDef> Symbol </th>
<td mat-cell *matCellDef="let element"> {{element.symbol}} </td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
</mat-table>
</div>
I have looked into the html, found the html has produced 4 exact table html elements, but why it just doens't show any data on each html element?
Don't go with complicated solution. Instead of that create a instance of "MatTableDataSource" and in MatTableDataSource having 'data' is the property so, you can directly assign the array to this.
I added a demo here stackblitz