I would use mat-table in my project
In my component file I use observable to catch data from DB and print them in my data table.
I tried to follow the official tutorial but nothing is printed on screen and I don't get error
export class ListeProjetsComponent implements OnInit {
constructor(private ajoutProj: AjoutprojService) { }
nouveauProjet: NouveauProjet[];
ngOnInit(){
this.getAllProj();
}
displayedColumns = ['name'];
dataSource = new MatTableDataSource<NouveauProjet>(this.nouveauProjet);
applyFilter(filterValue: string) {
filterValue = filterValue.trim(); // Remove whitespace
filterValue = filterValue.toLowerCase(); // MatTableDataSource defaults to lowercase matches
this.dataSource.filter = filterValue;
}
getAllProj() {
this.ajoutProj.getAllProj().subscribe(
response => {
this.nouveauProjet = response; console.log(this.nouveauProjet) // data is printed in the browser console. but not on screen
},
error => console.log(error)
);
}
}
Html file
<div class="example-container mat-elevation-z8">
<div class="example-header">
<mat-form-field>
<input matInput (keyup)="applyFilter($event.target.value)" placeholder="Filter">
</mat-form-field>
</div>
<mat-table #table [dataSource]="dataSource">
<ng-container matColumnDef="name">
<mat-header-cell *matHeaderCellDef> Name </mat-header-cell>
<mat-cell *matCellDef="let element"> {{element.nomProj}} </mat-cell>
</ng-container>
<mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
<mat-row *matRowDef="let row; columns: displayedColumns;"></mat-row>
</mat-table>
</div>
This might be happening because you initialize the table with an empty data set:
dataSource = new MatTableDataSource<NouveauProjet>(this.nouveauProjet);
At this point, this.nouveauProjet presumably does not contain any data;
Try re initializing the table data source when you get the data from your service:
getAllProj() {
this.ajoutProj.getAllProj().subscribe(
response => {
// set dataSource here
this.dataSource = new MatTableDataSource<NouveauProjet>(response);
},
error => console.log(error)
);
}
Related
I want to add a condition where the table should only show the table if table !== undefined and table has data but hiding the table causes the error.
The condition I am trying to implement is if table !== undefined and table.datasource.data is not empty or null and tableOptions.notifications is falsed show table
else if table !== undefined and table.datasource.data is empty and tableOptions.notifications is true then hide table else show
Any idea guys ? Thanks.
enter image description here
#error
core.js:6162 ERROR TypeError: Cannot read property 'actives' of undefined
at MatMultiSortTableDataSource.orderData (ngx-mat-multi-sort.js:795)
at TableData._clientSideSort (ngx-mat-multi-sort.js:428)
at TableData.set data [as data] (ngx-mat-multi-sort.js:479)
at TableMultiSortComponent.getData (table-multi-sort.component.ts:62)
at table-multi-sort.component.ts:51
at timer (zone-evergreen.js:2561)
at ZoneDelegate.invokeTask (zone-evergreen.js:406)
at Object.onInvokeTask (core.js:28497)
at ZoneDelegate.invokeTask (zone-evergreen.js:405)
at Zone.runTask (zone-evergreen.js:178)
#html code
<mat-card *ngIf="table !== undefined">
<div style="padding-top: 12px;" *ngIf="tableOptions.notifications">
<div class="alertInfo" >
<mat-icon>{{tableOptions.notifications[0].type}}</mat-icon>{{tableOptions.notifications[0].message}}
</div>
</div>
<mat-table mat-table [dataSource]="table.dataSource" matMultiSort (matSortChange)="table.onSortEvent()">
<ng-container *ngFor="let column of table.columns" [matColumnDef]="column.id">
<mat-header-cell class="table-multi-sort-header" *matHeaderCellDef [mat-multi-sort-header]="column.id">
<div>{{column.name}}</div>
<div class="sub-text">{{getColumnSubtitle(column.id)}}</div>
</mat-header-cell>
<mat-cell *matCellDef="let row">
<ng-container *ngIf="column.id !== 'action'; then col; else actionCol"></ng-container>
<ng-template #col>
<app-table-multi-sort-cell-default [cellData]="row" [id]="column.id" [subId]="getColumnSubId(column.id)"></app-table-multi-sort-cell-default>
</ng-template>
<ng-template #actionCol>
<app-table-multi-sort-cell-action [rowData]="row" [actions]="getActions(column.id)" (actionClickEvent)="clickTableAction($event,row)"></app-table-multi-sort-cell-action>
</ng-template>
</mat-cell>
</ng-container>
<mat-header-row *matHeaderRowDef="table.displayedColumns; sticky:true"></mat-header-row>
<mat-row *matRowDef="let item; columns: table.displayedColumns;"></mat-row>
</mat-table>
<mat-progress-bar *ngIf="isLoading" mode="indeterminate"></mat-progress-bar>
</mat-card>
#ts code
export class TableMultiSortComponent implements OnInit, OnChanges {
#Input() tableOptions:any;
#Input() tableMessage:any;
#Input() tableData:any = [];
test = 0;
#Input() isClientSide:boolean = false;
#Input() isLoading: boolean = false;
#Output() tableActionsEvent = new EventEmitter<any>();
#Output() dataServiceEvent = new EventEmitter<any>() ;
#ViewChild(MatMultiSort, { static: false }) sort: MatMultiSort;
hasInfoMessage: boolean;
tableConfig: any = TABLE_MULTI_SORT_OPTIONS.DEFAULT;
table:TableData<any>;
displayedColumns: any;
constructor() { }
ngOnChanges(changes: SimpleChanges): void {
}
ngOnInit(): void {
this.initTableMultiSort();
}
initTableMultiSort() {
this.tableConfig = {
...this.tableConfig,
...this.tableOptions
}
this.table = new TableData<any>(this.tableConfig.columns,this.tableConfig.sortParams);
this.table.pageSize = this.tableConfig.pageSize;
this.table.pageIndex = this.tableConfig.pageIndex;
this.table.nextObservable.subscribe(() => { this.getData(); });
this.table.sortObservable.subscribe(() => { this.getData(); });
this.table.previousObservable.subscribe(() => { this.getData(); });
this.table.sizeObservable.subscribe(() => { this.getData(); });
setTimeout(()=>{
this.table.dataSource = new MatMultiSortTableDataSource(this.sort, this.isClientSide);
this.getData();
console.log("this.tabl1e", this.table)
},0);
}
getData(){
this.table.totalElements = 1;
this.table.pageIndex = 0;
this.table.totalElements = 0;
this.table.pageSize = 10;
this.table.data = this.tableData;
if(this.dataServiceEvent) {
this.dataServiceEvent.emit(this.table);
}
}
getColumnSubtitle(id) :string{
return this.tableOptions.columns.filter(c => c.id === id)[0].subtitle;
}
getColumnSubId(id) :string{
return this.tableOptions.columns.filter(c => c.id === id)[0].subId;
}
getActions(id):any{
return this.tableOptions.columns.filter(c => c.id === id)[0].actions;
}
enter image description here
If you want to hide the table you shouldn't even instantiate the TableMultiSortComponent component.
Assuming the selector for that component is app-table-multi-sort you should add a *ngIf to it like:
<app-table-multi-sort *ngIf="tableData"></app-table-multi-sort>
I'm using 3 inputs to filter my data with a http request with searchvaluechanges and observable.
My problem is to filter the table with the data I get. The table is filled with a http GET when the dashboard is loaded.
Currently I'm not sure if mat-table is the best approach.
I can't see a way to make it work.
Dashboard.component.html
<div class="row align-items-end">
<div class="col">
<input (change)="searchValueChange()" [(ngModel)]="filter.articleNumber" id="search-box" matInput
placeholder="Articlenumber...">
<input (change)="searchValueChange()" [(ngModel)]="filter.name" matInput placeholder="Name...">
<input (change)="searchValueChange()" [(ngModel)]="filter.description" matInput placeholder="Description...">
</div>
</div>
<div class="row">
<div class="col">
<mat-table [dataSource]="articles" class="mat-elevation-z8">
<!-- ArticleNumber Column -->
<ng-container matColumnDef="articleNumber">
<mat-header-cell *matHeaderCellDef> Articlenumber</mat-header-cell>
<mat-cell *matCellDef="let article"> {{article.articleNumber}} </mat-cell>
</ng-container>
</mat-table>
</div>
</div>
Dashboard.component.ts
export class DashboardComponent implements OnInit {
public search$: Observable<ArticleSmall[]>;
public filter: ArticleFilter = {
articleNumber: '',
name: '',
description: ''
};
public articles: ArticleSmall[] = [];
public searchTerms: Subject<any> = new Subject<any>();
public dataSource = new MatTableDataSource(this.articles);
public displayedColumns: string[] = ['articleNumber', 'name', 'description', 'actions'];
constructor(private articleService: ArticleService) {
}
public ngOnInit(): void {
this.getArticles();
this.search$ = this.searchTerms.pipe(
debounceTime(300),
distinctUntilChanged(),
switchMap(() => this.articleService.search(this.filter.articleNumber, this.filter.name, this.filter.description)));
}
public searchValueChange(): void {
this.searchTerms.next(JSON.stringify(this.filter));
}
//this loads all articles with reduced information in the Dashboards Mat-Table
public getArticles(): void {
this.articleService.getAllArticles()
.pipe(
map((articles: Article[]) => articles.map((article: Article) => {
const newArticle: ArticleSmall = {
name: article.name,
articleNumber: article.articleNumber,
description: article.description
};
return newArticle;
}
))
).subscribe((data: ArticleSmall[]) => this.articles = data);
}
}
Well, you need to make a few changes :
Bind your data table to MatTableDataSource
<mat-table [dataSource]="dataSource" class="mat-elevation-z8">
<!-- ArticleNumber Column -->
<ng-container matColumnDef="articleNumber">
<mat-header-cell *matHeaderCellDef> Articlenumber</mat-header-cell>
<mat-cell *matCellDef="let article"> {{article.articleNumber}} </mat-cell>
</ng-container>
</mat-table>
Subscribe the $search to update MatTableDataSource's data.
public ngOnInit(): void {
// previous code
this.$search.subscribe(data=>{ // I assumed that your service returns the data not response itself.
this.dataSource.data = data;
});
}
Edit
3. Also you need to change your initial load of data as below :
public getArticles(): void {
this.articleService.getAllArticles()
.pipe(
map((articles: Article[]) => articles.map((article: Article) => {
const newArticle: ArticleSmall = {
name: article.name,
articleNumber: article.articleNumber,
description: article.description
};
return newArticle;
}
))
).subscribe((data: ArticleSmall[]) => this.dataSource.data = data);
}
Use the this.changeDetectorRefs.detectChanges() function when you get the data inside your subscribe method.
You need to inject ChangeDetectorRefs in the constructor.
You can find more info here
I have an angular PWA with a material table with data from firebase, the data is showned and the paginator is working but I also want to sort its data, but mat-sort doesn't work. It shows the arrow to sort the data, but when clicking the arrow the data is not sorted.
I have followed the documentation from Angular Material.
The table in the component template:
<ng-container matColumnDef="movimento">
<th mat-header-cell *matHeaderCellDef mat-sort-header>Tipo de movimento</th>
<td mat-cell *matCellDef="let movimento"> {{movimento.mapValue.fields.tipo_movimento.stringValue}}
</td>
</ng-container>
<ng-container matColumnDef="valor">
<th mat-header-cell *matHeaderCellDef mat-sort-header>Valor</th>
<td mat-cell *matCellDef="let movimento">
{{movimento.mapValue.fields.valor.doubleValue | number:'1.1-2'}}
{{movimento.mapValue.fields.valor.integerValue}} €
</td>
</ng-container>
<ng-container matColumnDef="data">
<th mat-header-cell *matHeaderCellDef mat-sort-header>Data</th>
<td mat-cell *matCellDef="let movimento"> {{movimento.mapValue.fields.data.timestampValue | date}}
</td>
</ng-container>
<ng-container matColumnDef="desc">
<th mat-header-cell *matHeaderCellDef mat-sort-header>Descrição</th>
<td mat-cell *matCellDef="let movimento"> {{movimento.mapValue.fields.desc.stringValue}}</td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="displayedColumns; sticky: true"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
</table>
<mat-paginator [pageSizeOptions]="[10, 20, 40]" showFirstLastButtons></mat-paginator>
The Component:
#Component({
selector: 'app-movimentar',
templateUrl: './visualizar-movimentos.component.html',
styleUrls: ['./visualizar-movimentos.component.css']
})
export class VisualizarMovimentosComponent implements OnInit {
user: firebase.User;
userData;
displayedColumns: string[] = ['movimento', 'valor', 'data', 'desc'];
dataSource = new MatTableDataSource<Movimentos>();
#ViewChild(MatPaginator, { static: false })
set paginator(value: MatPaginator) {
this.dataSource.paginator = value;
}
#ViewChild(MatSort, { static: false }) sort: MatSort;
constructor(private auth: AuthService,
private router: Router,
private afs: AngularFirestore) { }
ngOnInit() {
this.auth.getUserState()
.subscribe(user => {
this.user = user;
this.getUserData();
});
}
/* loadLessonsPage() {
this.dataSource._orderData;
debugger
} */
getUserData(): void {
this.auth.getUserData(this.user.uid)
.subscribe(user => {
this.userData = user;
this.dataSource = new MatTableDataSource(this.userData._document.proto.fields.movimentos.arrayValue.values);
this.dataSource.paginator = this.paginator;
this.dataSource.sort = this.sort;
});
}
login() {
this.router.navigate(['login']);
}
logout() {
this.auth.logout();
this.router.navigate(['inicio']);
}
register() {
this.router.navigate(['/register']);
}
trackByUid(index, item) {
return item.uid;
}
}```
Thanks for the help in advance.
The problem was with the data from firebase, it was not compatible with the mat sort. To solve it you need a map like this one:
Here's the map
return data.reduce((acc, value) => {
return [
...acc,
Object.entries(value.mapValue.fields).reduce((accValue, [key, value]) => {
return {
...accValue,
[key]: Object.values(value)[0]
}
}, {})
]
}, [])
}
you need to specify mat sort in your table like this and on the columns on which you want to sort the data.
<table matSort (matSortChange)="sortData($event)">
</table>
for sort on column
<th mat-header-cell *matHeaderCellDef mat-sort-header>
On your .ts file
#ViewChild(MatSort, { static: false }) set content(content: ElementRef) {
this.sort = content;
if (this.sort) {
this.dataSource.sort = this.sort;
}
}
And you have already done this part when you load data
getUserData(): void {
this.auth.getUserData(this.user.uid)
.subscribe(user => {
this.userData = user;
this.dataSource = new MatTableDataSource(this.userData._document.proto.fields.movimentos.arrayValue.values);
this.dataSource.paginator = this.paginator;
this.dataSource.sort = this.sort;
});
}
It should work now!
I'm trying to display some data in angular material data-table,my service class method has data but its not displaying in data-table, please help me ,am unable to find mistake in data-table from last 3 hours
service class and api
getfriendAnswers(id: number): Observable<FriendDetails[]> {
debugger;
return this.httpClient.get<FriendDetails[]>(this.apiUrl + '/Questions/yourFriendAnswerdCount/' + id)
}
[HttpGet, Route("yourFriendAnswerdCount/{id}")]
public ActionResult getFriendAnswerdCount(int id)
{
return Ok(userRepository.getFriendAnswerdCount(id));
}
friend details class
export interface FriendDetails {
Id: number;
UserId: number;
AnsweredCount: number;
FriendName: string;
}
component class
export class FriendAnswredComponent implements OnInit {
id;
constructor(private service: UserService,private route: ActivatedRoute) { }
dataSource :FriendDetails[]=[];
displayedColumns: string[] = [ 'FriendName', 'AnsweredCount',];
ngOnInit() {
this.id = parseInt(this.route.snapshot.paramMap.get('id'));
this.service.getfriendAnswers(this.id).subscribe(b => {
debugger;
this.dataSource = b;
});
}
}
material data-table template
<mat-card>
<mat-card-title>your friends answered count questions are</mat-card-title>
<mat-card-content>
<div *ngIf="dataSource">
<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" -->
<!-- Name Column -->
<ng-container matColumnDef="FriendName">
<th mat-header-cell *matHeaderCellDef> FriendName </th>
<td mat-cell *matCellDef="let element"> {{element.FriendName}} </td>
</ng-container>
<!-- Weight Column -->
<ng-container matColumnDef="AnsweredCount">
<th mat-header-cell *matHeaderCellDef> AnsweredCount </th>
<td mat-cell *matCellDef="let element"> {{element.AnsweredCount}} </td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
</table>
</div>
</mat-card-content>
</mat-card>
{{dataSource[0]?.AnsweredCount}}
service returns this output
{id: 5, userId: 11, answeredCount: 2, friendName: "sarala"}
I'm getting empty data table even service returns data
you are trying to bind dataSource[0]?.AnsweredCount when AnsweredCount does not exist in your object.
It should be answeredCount, not AnsweredCount:
{{dataSource[0]?.answeredCount}}
I am creating a table using table Angular material
for reference I am using this example https://material.angular.io/components/table/examples
Here is what I have so far:
HTML
<mat-form-field>
<input matInput (keyup)="applyFilter($event.target.value)" placeholder="Filter">
</mat-form-field>
<div class="mat-elevation-z8">
<table mat-table [dataSource]="dataSource" matSort>
<ng-container matColumnDef="name">
<th mat-header-cell *matHeaderCellDef mat-sort-header> Name </th>
<td mat-cell *matCellDef="let row"> {{row.name}} </td>
</ng-container>
<ng-container matColumnDef="id">
<th mat-header-cell *matHeaderCellDef mat-sort-header> Id </th>
<td mat-cell *matCellDef="let row"> {{row.id}} </td>
</ng-container>
<ng-container matColumnDef="release">
<th mat-header-cell *matHeaderCellDef mat-sort-header> Release</th>
<td mat-cell *matCellDef="let row"> {{row.first_air_date}} </td>
</ng-container>
<ng-container matColumnDef="description">
<th mat-header-cell *matHeaderCellDef mat-sort-header> Description </th>
<td mat-cell *matCellDef="let row" [style.color]="row.color"> {{row.overview}} </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]"></mat-paginator>
</div>
Component .ts
import { Component, ViewChild, OnInit } from '#angular/core';
import { MoviesService } from '../movies.service';
import { MatPaginator, MatSort, MatTableDataSource } from '#angular/material';
import { DatatableComponent } from '#swimlane/ngx-datatable';
#Component({
selector: 'app-tv-shows',
templateUrl: './tv-shows.component.html',
styleUrls: ['./tv-shows.component.scss']
})
export class TvShowsComponent implements OnInit {
displayedColumns: string[] = ['name', 'id', 'release', 'description'];
dataSource: any;
#ViewChild(DatatableComponent) table: DatatableComponent;
constructor(private moviesService: MoviesService) {
this.moviesService.getPopularTVShows().subscribe(res => {
this.dataSource = res.results;
});
}
#ViewChild(MatPaginator) paginator: MatPaginator;
#ViewChild(MatSort) sort: MatSort;
ngOnInit() {
this.dataSource.paginator = this.paginator;
this.dataSource.sort = this.sort;
}
applyFilter(filterValue: string) {
this.dataSource.filter = filterValue.trim().toLowerCase();
if (this.dataSource.paginator) {
this.dataSource.paginator.firstPage();
}
}
}
when I run my app data are displayed in a table perfectly but I get the following error :
ERROR TypeError: Cannot set property 'paginator' of undefined
So nothing works at all neither sorting , filtering or pagination
I need some help here:
What am I doing wrong in my codes above? Any help will be appreciated.
The error says that you're trying to assign this.dataSource.paginator when this.dataSource is still undefined. Do the assignment after it was initalized.
Also, when you want to use the paginator, sort or a filter, you have to use the MatTableDataSource class for it. It's not enough to use raw data as your dataSource:
ngOnInit() {
this.moviesService.getPopularTVShows().subscribe(res => {
// Use MatTableDataSource for paginator
this.dataSource = new MatTableDataSource(res.results);
^^^^^^^^^^^^^^^^^^
// Assign the paginator *after* dataSource is set
this.dataSource.paginator = this.paginator;
this.dataSource.sort = this.sort;
});
}
You are not doing anything wrong. assign new instance to ur dataSource just like below code.dataSource: MatTableDataSource<Order> = new MatTableDataSource();
and also thanks to Kim Kern for your explanation
export class OrdersComponent implements OnInit {
displayedColumns: string[] = ['Id', 'Description', 'Status', 'Date', 'Total Price'];
dataSource: MatTableDataSource<Order> = new MatTableDataSource();
#ViewChild(MatPaginator) paginator!: MatPaginator;
#ViewChild(MatSort) sort!: MatSort;
constructor(private orderService:OrderService) { }
export class DisplayapplicationsComponent {
constructor(private authService: AuthService, private pndService: PndService, private cdref: ChangeDetectorRef) { }
listOfApplications: any;
isTableHasData = true;
private paginator: MatPaginator;
private sort: MatSort;
dataSource: MatTableDataSource<any>;
displayedColumns: string[] = ['apprefno', 'orgname', 'ackowledgeNo', 'contactpersonName'];
#ViewChild(MatSort) set matSort(ms: MatSort) {
if( ms != undefined)
{
this.sort = ms;
this.setDataSourceAttributes();
}
}
#ViewChild(MatPaginator) set matPaginator(mp: MatPaginator) {
if(mp != undefined)
{
this.paginator = mp;
this.setDataSourceAttributes();
}
}
setDataSourceAttributes() {
this.dataSource = new MatTableDataSource( this.listOfApplications['data']);
this.dataSource.paginator = this.paginator;
this.dataSource.sort = this.sort;
this.cdref.detectChanges();
}
ngOnInit(): void {
this.getApplications();
}
getApplications = () => {
let userId = this.authService.getUserId();
const regex = new RegExp('[A-Z]{5}[0-9]{4}[A-Z]{1}');
let inputdata = regex.test(userId) ? { 'panno': userId } : { 'branchCode': this.authService.getBOOffice(), 'applicationstatus': 'P' };
this.pndService.getApplications(inputdata).subscribe((response: any) => {
this.listOfApplications = response;
});
}
applyFilter(filterValue: string) {
this.dataSource.filter = filterValue.trim().toLowerCase();
if (this.dataSource.paginator) {
this.dataSource.paginator.firstPage();
}
if (this.dataSource.filteredData.length > 0) {
this.isTableHasData = true;
} else {
this.isTableHasData = false;
}
}
}