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>
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'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;
}
}
}
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)
);
}