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>
Related
I have a mat table with a filter that uses chips to filter multiple criterias.
When I go to filter the first time and save the criteria,I get the error ExpressionChangedAfterItHasBeenCheckedError. It says it went from undefined to a number.
I've seen in multiple treads saying that I need to change the way I initialize the table and data to be loaded to the table. I've added ngAfterContentChecked() with this.ref.detectChanges(); and it gets rid of the error, but not the wrong behavior.
I start with ngOnInit getting the data from a service.
What should I do to get the correct behavior?
See the code attached!
thanks!
DetentionValidation.component.ts
import { AfterViewInit, Component, ViewChild, OnInit } from '#angular/core';
import { MatSort, Sort } from '#angular/material/sort';
import { MatTableDataSource } from '#angular/material/table';
import { LiveAnnouncer } from '#angular/cdk/a11y';
import { COMMA, ENTER } from '#angular/cdk/keycodes';
import { MatChipInputEvent } from '#angular/material/chips';
import { SelectionModel } from '#angular/cdk/collections';
import { DetentionValidationService } from './detentionValidation.service';
import { Subscription } from 'rxjs';
import { centerInterface } from './centers-data.model';
import { StopsInterface } from './stops-data.model';
import { ChangeDetectorRef } from '#angular/core';
import { parse } from 'dotenv';
//data interfaces
interface operation {
value: string;
viewValue: string;
}
// export interface StopsInterface {
// StopNbr: number;
// Wgt: number;
// }
export interface SearchItem {
name: string;
}
#Component({
selector: 'app-detentionValidation',
templateUrl: './detentionValidation.component.html',
styleUrls: ['./detentionValidation.component.css'],
})
export class DetentionValidationComponent implements AfterViewInit, OnInit {
isLoading = true;
selectedCenter!: string;
selectedOperation!: string;
operations: operation[] = [
{ value: 'Pickup', viewValue: 'Pickup' },
{ value: 'Delivery', viewValue: 'Delivery' },
];
centers: centerInterface[] = [];
stops: StopsInterface[] = [];
private allDataSubs: Subscription;
//which rows are selected
selection = new SelectionModel<StopsInterface>(true, []);
public globalFilter = '';
public searchItems: SearchItem[] = [];
public reset_data = this.stops;
displayedColumns: string[] = [
'WAND_STOP_NBR',
'UNIT_NBR',
'AGGR_SHP_WGT',
'select',
];
dataSource = new MatTableDataSource(this.stops);
stopsDataSource = [];
selectable = true;
removable = true;
readonly separatorKeysCodes: number[] = [COMMA, ENTER];
public searchTerms: string[] = [];
constructor(
private _liveAnnouncer: LiveAnnouncer,
public detentionValidationService: DetentionValidationService,
private ref: ChangeDetectorRef
) {}
#ViewChild(MatSort, { static: false }) set content(sort: MatSort) {
this.dataSource.sort = sort;
}
ngAfterViewInit() {}
async ngOnInit() {
const response = await this.detentionValidationService.getCenters();
//loading Service centers for drop down
this.detentionValidationService
.getCentersUpdateListener()
.subscribe((centers: centerInterface[]) => {
this.centers = centers;
// this.isLoading = false;
});
//loading all data
this.detentionValidationService
.getStopsUpdateListener()
.subscribe((stops: StopsInterface[]) => {
stops.forEach((element) => {
this.stops.push({
WAND_STOP_NBR: element.WAND_STOP_NBR,
UNIT_NBR: element.UNIT_NBR,
AGGR_SHP_WGT: element.AGGR_SHP_WGT,
});
console.log(element.WAND_STOP_NBR);
});
this.stopsDataSource = this.stops;
this.dataSource.data = this.stopsDataSource;
// this.dataSource.filterPredicate = this.customFilterPredicate();
this.isLoading = false;
});
}
ngAfterContentChecked() {
this.dataSource.sort = this.dataSource.sort;
this.dataSource.filterPredicate = this.customFilterPredicate();
this.ref.detectChanges();
}
onStopToggled(stop: StopsInterface) {
this.selection.toggle(stop);
// console.log(this.selection.selected);
}
isAllSelected() {
return (
// console.log(this.dataSource.filteredData),
this.selection.selected?.length == this.dataSource.filteredData.length
);
}
toggleAll() {
if (this.isAllSelected()) {
this.selection.clear();
} else {
this.selection.select(...this.dataSource.filteredData);
}
}
add(event: MatChipInputEvent): void {
const input = event.chipInput.inputElement;
const value = event.value;
// Add new search term
if ((value || '').trim()) {
this.searchItems.push({ name: value.trim() });
}
// Reset the input value
if (input) {
input.value = '';
}
this.searchTerms = this.searchItems.map(function (searchItem) {
return searchItem.name;
});
this.globalFilter = '';
// console.log('search terms', this.searchTerms);
}
remove(item: SearchItem): void {
const index = this.searchItems.indexOf(item);
if (index >= 0) {
this.searchItems.splice(index, 1);
this.searchTerms = this.searchItems.map(function (searchItem) {
return searchItem.name;
});
this.dataSource.data = [...this.reset_data];
this.dataSource.filter = JSON.stringify(this.searchTerms);
}
}
applyFilter(filterValue: string) {
console.log(filterValue);
this.globalFilter = filterValue;
this.dataSource.filter = JSON.stringify(this.searchTerms);
}
customFilterPredicate() {
const myFilterPredicate = (
data: StopsInterface,
filter: string
): boolean => {
var globalMatch = !this.globalFilter;
if (this.globalFilter) {
// search all text fields
globalMatch =
data.WAND_STOP_NBR.toString()
.trim()
.toLowerCase()
.indexOf(this.globalFilter.toLowerCase()) !== -1 ||
data.UNIT_NBR.toString()
.trim()
.toLowerCase()
.indexOf(this.globalFilter.toLowerCase()) !== -1 ||
data.AGGR_SHP_WGT.toString()
.trim()
.toLowerCase()
.indexOf(this.globalFilter.toLowerCase()) !== -1;
}
if (!globalMatch) {
return false;
}
let parsedSearchTerms = JSON.parse(filter);
let isMatchToAllTerms = true;
for (const term of parsedSearchTerms) {
isMatchToAllTerms =
isMatchToAllTerms &&
(data.WAND_STOP_NBR.toString()
.toLowerCase()
.trim()
.indexOf(term.toLowerCase()) !== -1 ||
data.UNIT_NBR.toString()
.toLowerCase()
.trim()
.indexOf(term.toLowerCase()) !== -1 ||
data.AGGR_SHP_WGT.toString()
.toLowerCase()
.trim()
.indexOf(term.toLowerCase()) !== -1);
}
return isMatchToAllTerms;
};
return myFilterPredicate;
}
announceSortChange(sortState: Sort) {
if (sortState.direction) {
this._liveAnnouncer.announce(`Sorted ${sortState.direction}ending`);
console.log('sorting');
} else {
this._liveAnnouncer.announce('Sorting cleared');
}
}
}
DetentionValidation.component.html
<body>
<div
style="
position: absolute;
height: 80%;
width: 80%;
align-items: center;
display: flex;
justify-content: space-around;
align-content: space-around;
"
>
<mat-spinner *ngIf="isLoading">
<span class="sr-only">Loading...</span>
</mat-spinner>
</div>
<div *ngIf="!isLoading">
<div>
<form>
<div>
<h2>Detention Processing Validation</h2>
<div style="display: flex">
<div style="padding-right: 2%">
<mat-form-field appearance="fill">
<mat-label>Select Service Center</mat-label>
<mat-select [(ngModel)]="selectedCenter" name="car">
<mat-option
*ngFor="let center of centers"
[value]="center.ORIG_LOC_CD"
>
{{ center.ORIG_LOC_CD }}
</mat-option>
</mat-select>
</mat-form-field>
<p>Selected SC: {{ selectedCenter }}</p>
</div>
<div>
<mat-form-field appearance="fill">
<mat-label>Pickup/Delivery</mat-label>
<mat-select [(ngModel)]="selectedOperation" name="operation">
<mat-option
*ngFor="let operation of operations"
[value]="operation.value"
>
{{ operation.viewValue }}
</mat-option>
</mat-select>
</mat-form-field>
<p>Selected Operation: {{ selectedOperation }}</p>
</div>
<div class="fedex-button-row">
<button mat-raised-button color="primary">Submit</button>
</div>
</div>
</div>
</form>
</div>
<!-- table div -->
<div class="stops-table-div">
<mat-chip-list #chipList>
<mat-chip
*ngFor="let item of searchItems"
[selectable]="selectable"
[removable]="removable"
(removed)="remove(item)"
>
{{ item.name }}
<mat-icon matChipRemove *ngIf="removable"> cancel </mat-icon>
</mat-chip>
</mat-chip-list>
<mat-form-field>
<input
matInput
[ngModel]="globalFilter"
(ngModelChange)="applyFilter($event)"
[matChipInputFor]="chipList"
[matChipInputSeparatorKeyCodes]="separatorKeysCodes"
(matChipInputTokenEnd)="add($event)"
placeholder="Search (press enter for multiple)"
class="form-control input-md"
appearance="fill"
/>
</mat-form-field>
<table
mat-table
class="stops-table mat-elevation-z8"
[dataSource]="dataSource"
matSort
(matSortChange)="announceSortChange($event)"
>
<ng-container matColumnDef="WAND_STOP_NBR">
<th
mat-header-cell
*matHeaderCellDef
mat-sort-header
sortActionDescription="Sort by WAND_STOP_NBR"
>
Stop Nbr
</th>
<td mat-cell *matCellDef="let stop">{{ stop.WAND_STOP_NBR }}</td>
</ng-container>
<ng-container matColumnDef="UNIT_NBR">
<th
mat-header-cell
*matHeaderCellDef
mat-sort-header
sortActionDescription="Sort by UNIT_NBR"
>
Unit Nbr
</th>
<td mat-cell *matCellDef="let stop">{{ stop.UNIT_NBR }}</td>
</ng-container>
<ng-container matColumnDef="AGGR_SHP_WGT">
<th
mat-header-cell
*matHeaderCellDef
mat-sort-header
sortActionDescription="Sort by AGGR_SHP_WGT"
>
Weight
</th>
<td mat-cell *matCellDef="let stop">{{ stop.AGGR_SHP_WGT }}</td>
</ng-container>
<ng-container matColumnDef="select">
<th mat-header-cell *matHeaderCellDef>
<mat-checkbox
color="primary"
[checked]="selection.hasValue() && isAllSelected()"
(change)="toggleAll()"
[indeterminate]="selection.hasValue() && !isAllSelected()"
>
</mat-checkbox>
</th>
<td mat-cell *matCellDef="let stop">
<mat-checkbox
color="primary"
(change)="onStopToggled(stop)"
[checked]="selection.isSelected(stop)"
>
</mat-checkbox>
</td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
<tr mat-row *matRowDef="let stop; columns: displayedColumns"></tr>
</table>
</div>
</div>
</body>
From https://angular.io/errors/NG0100
If the issue exists within ngAfterViewInit, the recommended solution is to use a constructor or ngOnInit to set initial values, or use ngAfterContentInit for other value bindings.
So, you can try to
[...]
export class DetentionValidationComponent implements AfterContentInit {
[...]
ngAfterContentInit () {
//insert content of your ngOnInit
}
In every case, this is just a dev error, in production there is no additional check and no errors throws
I have a reusable table the [cellData]="row" populate each cell on the table (sample table is on the screenshot).
What I want is how to we replace the null values on the template with "---" so that instead of displaying nothing on the cell if value is empty I wanna display "---".
Is it possible to do it in <app-table-multi-sort-cell-default [cellData]="row" [id]="column.id" [subId]="getColumnSubId(column.id)" [columnName]="column.name"></app-table-multi-sort-cell-default> so I don't have to modify the row objects and just do it in the template. Thanks for any help.
#table-multi-sort.component.html code
<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" (click)="editRow(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)" [columnName]="column.name"></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>
enter image description here
#table-multi-sort-cell-default.component.html
<div>{{cellData[id]}}</div>
<div class="cellSubText secondary-text">{{cellData[subId]}}</div>
#table-multi-sort-cell-default.component.ts
export class TableMultiSortCellDefaultComponent implements OnInit {
#Input() cellData:any;
#Input() id: any;
#Input() subId:any;
#Input() columnName: any;
constructor() { }
ngOnInit(): void {
}
}
You can create a simple function for handling null values:
export class TableMultiSortCellDefaultComponent implements OnInit {
#Input() cellData:any;
#Input() id: any;
#Input() subId:any;
#Input() columnName: any;
constructor() { }
ngOnInit(): void {
}
public customFunc(row: any, columnId: any) {
row[columnId] = row[columnId] == null ? '---' : row[columnId];
return row;
}
}
And in the template:
<app-table-multi-sort-cell-default
[cellData]="customFunc(row, column.id)"
[id]="column.id"
[subId]="getColumnSubId(column.id)"
[columnName]="column.name">
</app-table-multi-sort-cell-default>
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 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;
}
}
}
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)
);
}