2

I'm currently working to create a reusable component for angular material table. I've been manage to create a reusable component for the table.

I wanted to make the change the header in *matHeaderCellDef as it is defined:

columnHeader = ['studendID', 'fname', 'weight', 'symbol'];

for example: change the studentID to Student ID and fname to First Name int the table header.

enter image description here

Now the problem is I can't manage to change the table header.


Please see the code that I have done so far.

data-table.component.html

<mat-form-field>
  <input matInput (keyup)="applyFilter($event.target.value)" placeholder="Filter">
</mat-form-field>
<table mat-table [dataSource]="dataSource" matSort class="mat-elevation-z8">

  <ng-container [matColumnDef]="tableData" *ngFor="let tableData of columnHeader">
    <th mat-header-cell *matHeaderCellDef mat-sort-header> {{tableData}}    </th>
    <td mat-cell *matCellDef="let element"> {{element[tableData] }}</td>
  </ng-container>

  <tr mat-header-row *matHeaderRowDef="columnHeader"></tr>
  <tr mat-row *matRowDef="let row; columns: columnHeader;"></tr>
</table>

data-table.component.ts

import {Component, OnInit, ViewChild, Input} from '@angular/core';
import {MatSort, MatTableDataSource, MatTable} from '@angular/material';

@Component({
  selector: 'app-data-table',
  templateUrl: './data-table.component.html',
  styleUrls: ['./data-table.component.css']
})
export class DataTableComponent implements OnInit {
  @Input() tableData;
  @Input() columnHeader;
  
  dataSource;

  @ViewChild(MatSort) sort: MatSort;

  ngOnInit() {
    console.log(this.tableData);
    this.dataSource = new MatTableDataSource(this.tableData);
    this.dataSource.sort = this.sort;
    
  }

  applyFilter(filterValue: string) {
    this.dataSource.filter = filterValue.trim().toLowerCase();
  }
}

employee.component.html

<app-data-table [tableData]="tableData" [columnHeader]="columnHeader"></app-data-table>

employee.component.ts

import { Component, OnInit } from '@angular/core';
import { DataTableComponent } from '../shared/data-table/data-table.component';

export interface PeriodicElement {
  fname: string;
  studendID: number;
  weight: number;
  symbol: string;
}



@Component({
  selector: 'app-employee',
  templateUrl: './employee.component.html',
  styleUrls: ['./employee.component.css']
})
export class EmployeeComponent implements OnInit {

  constructor() { }

  ngOnInit() {
  }

  columnHeader = ['studendID', 'fname', 'weight', 'symbol'];

  tableData: PeriodicElement[] = [
    {studendID: 1, fname: 'Hydrogen', weight: 1.0079, symbol: 'H'},
    {studendID: 2, fname: 'Helium', weight: 4.0026, symbol: 'He'},
    {studendID: 3, fname: 'Lithium', weight: 6.941, symbol: 'Li'},
    {studendID: 4, fname: 'Beryllium', weight: 9.0122, symbol: 'Be'},
    {studendID: 5, fname: 'Boron', weight: 10.811, symbol: 'B'},
    {studendID: 6, fname: 'Carbon', weight: 12.0107, symbol: 'C'},
    {studendID: 7, fname: 'Nitrogen', weight: 14.0067, symbol: 'N'},
    {studendID: 8, fname: 'Oxygen', weight: 15.9994, symbol: 'O'},
    {studendID: 9, fname: 'Fluorine', weight: 18.9984, symbol: 'F'},
    {studendID: 10, fname: 'Neon', weight: 20.1797, symbol: 'Ne'},
  ];

}


Please see the Stackblitz Link for the live code.

4 Answers 4

5

I hope this will help you! (You have to change the html to get the title)

employee.component.ts

Keep columnHeader as an object instead of an array. Or you can extend it to an array of objects to mention extra information like, pipes, render as html etc.,

columnHeader = {'studentID': 'ID', 'fname': 'First Name', 'lname': 'Last Name', 'weight': 'Weight', 'symbol': 'Code'};

data-table.component.html

<ng-container [matColumnDef]="tableData" *ngFor="let tableData of objectKeys(columnHeader)">
    <th mat-header-cell *matHeaderCellDef mat-sort-header> {{columnHeader[tableData]}}    </th>
    <td mat-cell *matCellDef="let element"> {{element[tableData] }}</td>
  </ng-container>

  <tr mat-header-row *matHeaderRowDef="objectKeys(columnHeader)"></tr>
  <tr mat-row *matRowDef="let row; columns: objectKeys(columnHeader);"></tr>

data-table.component.ts

@Input() columnHeader;
objectKeys = Object.keys;

StackBlitz

Sign up to request clarification or add additional context in comments.

2 Comments

Thanks. I think using Object.keys solves my problem.
@davecar21 haw can I display last column data according to conditions like some data table needs "Edit", "Delete" button, but some of data tables, don't need.
0

I would suggest the simplest way. You can define function to get header name like below

HTML:

<ng-container [matColumnDef]="tableData" *ngFor="let tableData of columnHeader">
    <th mat-header-cell *matHeaderCellDef mat-sort-header> {{getHeader(tableData)}}    </th>
    <td mat-cell *matCellDef="let element"> {{element[tableData] }}</td>
  </ng-container>

TS:

getHeader(tableData) {
    if(tableData === "studendID")
      return "Student ID";
    if(tableData === "fname")
      return "First Name";
    return tableData;
  }

2 Comments

Thanks for this, I got an idea. The problem is that I can't touch the code of the data-table.component. I wanted to pass parameters to the employee.component.
can't you even touch its HTML file? @davecar21
0

Little enhancement over Shreenil's answer:

<ng-container [matColumnDef]="tableData" *ngFor="let tableData of columnHeader">
    <th mat-header-cell *matHeaderCellDef mat-sort-header> 
    {tableData, select, 
        studentid {Student ID}
        fname {First Name}
    }
    </th>
    <td mat-cell *matCellDef="let element"> {{element[tableData] }}</td>
</ng-container>

The fewer bindings you have in your template the more performant rendering you achieve.

Comments

0

Another simple way to achieve this is, create a map having Map<field, properties> and one of your property can be a label for each column like so you can have very dynamic control over field, its properties, and its behavior.

  <ng-container [matColumnDef]="tableData" *ngFor="let tableData of objectKeys(columnHeader)">
    <th mat-header-cell *matHeaderCellDef mat-sort-header> 
      {{ myMap.get(tableData).label }}    
    </th>
    <td mat-cell *matCellDef="let element"> 
       {{element[tableData] }}
    </td>
  </ng-container>
  <tr mat-header-row *matHeaderRowDef="objectKeys(columnHeader)"></tr>
  <tr mat-row *matRowDef="let row; columns: objectKeys(columnHeader);"></tr>

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.