angular5 material can't show any data in table - angular-material

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

Related

Angular Material v13 Table not Sorting

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.

Angular Material Row when looping through data

My Data Source is like below
[{"isGroup":true,"groupName":"MV Reddy","items":[{"id":1,"name":"MV Reddy","verticalid":5,"vertical":"Colocation - Large > 20 Racks","target":"150","sap":"80","colo":"20","others":"50","quarter":1,"year":2019},{"id":10,"name":"MV Reddy","verticalid":6,"vertical":"Govt","target":"150","sap":"80","colo":"20","others":"50","quarter":1,"year":2020}]},{"isGroup":true,"groupName":"Neeraj Jha","items":[{"id":2,"name":"Neeraj Jha","verticalid":4,"vertical":"Alliances","target":"70","sap":"20","colo":"30","others":"20","quarter":2,"year":2019},{"id":5,"name":"Neeraj Jha","verticalid":4,"vertical":"Alliances","target":"150","sap":"80","colo":"20","others":"50","quarter":1,"year":2019}]},{"isGroup":false,"groupName":"Suresh Rathod","items":[{"id":3,"name":"Suresh Rathod","verticalid":3,"vertical":"C4C India (Public Cloud)","target":"100","sap":"20","colo":"30","others":"50","quarter":1,"year":2019}]},{"isGroup":false,"groupName":"Arun Dubey","items":[{"id":4,"name":"Arun Dubey","verticalid":6,"vertical":"Govt","target":"150","sap":"80","colo":"20","others":"50","quarter":4,"year":2019}]},{"isGroup":true,"groupName":"Atin Singh","items":[{"id":6,"name":"Atin Singh","verticalid":5,"vertical":"Colocation - Large > 20 Racks","target":"150","sap":"80","colo":"20","others":"50","quarter":1,"year":2020},{"id":7,"name":"Atin Singh","verticalid":2,"vertical":"IAAS and Rest of Ctrls Services","target":"150","sap":"80","colo":"20","others":"50","quarter":1,"year":2020},{"id":8,"name":"Atin Singh","verticalid":3,"vertical":"C4C India (Public Cloud)","target":"150","sap":"80","colo":"20","others":"50","quarter":1,"year":2020},{"id":9,"name":"Atin Singh","verticalid":6,"vertical":"Govt","target":"150","sap":"80","colo":"20","others":"50","quarter":1,"year":2020}]}]
and I wrote/printing my Table like this:
<table class="mat-elevation-z8 " mat-table matSort [dataSource]='targetData' (matSortChange)="sortData($event)">
<ng-container matColumnDef="Employee">
<th mat-header-cell *matHeaderCellDef mat-sort-header> Employee </th>
<td mat-cell *matCellDef="let element"> {{element.items[0].name}}
</td>
</ng-container>
<ng-container matColumnDef="groupData">
<ng-container *matCellDef="let group">
<ng-container *ngFor="let groupCol of group.items;index as i;">
<ng-container *ngIf="i==0 else newRow;">
<td mat-cell rowspan="group.items.length">
{{group.groupName}}
</td>
<td mat-cell>
{{groupCol.vertical}}
</td>
<td mat-cell>
{{groupCol.target}}
</td>
<td mat-cell>
{{groupCol.sap}}
</td>
<td mat-cell>
{{groupCol.colo}}
</td>
<td mat-cell>
{{groupCol.others}}
</td>
</ng-container>
<ng-template #newRow>
<tr mat-row>
<td mat-cell>
{{groupCol.vertical}}
</td>
<td mat-cell>
{{groupCol.target}}
</td>
<td mat-cell>
{{groupCol.sap}}
</td>
<td mat-cell>
{{groupCol.colo}}
</td>
<td mat-cell>
{{groupCol.others}}
</td>
</tr>
</ng-template>
</ng-container>
</ng-container>
</ng-container>
<ng-container matColumnDef="Vertical">
<th mat-header-cell *matHeaderCellDef>Vertical</th>
<td mat-cell *matCellDef="let element"> {{element.items[0].vertical}} </td>
</ng-container>
<ng-container matColumnDef="Target">
<th mat-header-cell *matHeaderCellDef>Target</th>
<td mat-cell *matCellDef="let element"> {{element.items[0].target}} </td>
</ng-container>
<ng-container matColumnDef="SAP">
<th mat-header-cell *matHeaderCellDef>SAP</th>
<td mat-cell *matCellDef="let element">{{element.items[0].sap}}</td>
</ng-container>
<ng-container matColumnDef="COLO">
<th mat-header-cell *matHeaderCellDef>COLO</th>
<td mat-cell *matCellDef="let element">{{element.items[0].colo}}</td>
</ng-container>
<ng-container matColumnDef="Others">
<th mat-header-cell *matHeaderCellDef>Others</th>
<td mat-cell *matCellDef="let element">{{element.items[0].others}}</td>
</ng-container>
<ng-container matColumnDef="Action">
<th mat-header-cell *matHeaderCellDef mat-sort-header> Action </th>
<td mat-cell *matCellDef="let element">
<div class="tableActions ">
<button class="view mat-button" (click)='edit(element.items[0])'>
<i class="material-icons">
create
</i>
</button>
</div>
</td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="TargetTable;"></tr>
<tr mat-row *matRowDef="let row; columns: TargetTable;"></tr>
<tr mat-row *matRowDef="let row; columns: ['groupData']; when: isAGroup"></tr>
</table>
I am unable to print another row inside a table while looping through my data
Final result should be like below.
Your approach goes in the right direction as you're using the rowspan attribute. The template however is unnecessary complex and can be simplified if you pre-process your data.
I solved a similar problem in the open source project Koia using a RowSpanComputer class. Within summary-table.component.html, the computed row spans are then used to define the rowspan attribute of the td element.
[attr.rowspan]="rowSpans[iCol][iRow].span"
The RowSpanComputer class computes the rowspan for each cell out of the specified table data (array of rows). It basically loops over the rows and increments the rowspan for cells as long as their value remains unchanged and left located cells were also spanned. As soon as the value changes, the corresponding rowspan is reset to zero.
Please have a look at the following StackBlitz that uses the data you provided. This must obviously further be refined in order to obtain the result you expect.
UPDATE
If you want to have rowspan applied for cells even if left located cells were not spanned, simply remove the following line from the RowSpanComputer class.
spanColumnContexts.slice(iCol + 1).forEach(c => c.spannedRow = {});
I did this in this StackBlitz where a renamed RowSpanComputer to GroupingRowSpanComputer in order to avoid confusion.
My Table:
<table mat-table matSort [dataSource]="targetData" class="mat-elevation-z8">
<ng-container matColumnDef="Employee">
<th mat-header-cell *matHeaderCellDef mat-sort-header> Employee </th>
<td mat-cell *matCellDef="let element" [attr.rowspan]="rowSpanLength(element)"
[style.display]="rowSpanLength(element)>0 ? '' : 'none'">
{{element.name}}
</td>
</ng-container>
<ng-container matColumnDef="Vertical">
<th mat-header-cell *matHeaderCellDef mat-sort-header> Vertical </th>
<td mat-cell *matCellDef="let element"> {{element.vertical}}
</td>
</ng-container>
<ng-container matColumnDef="Target">
<th mat-header-cell *matHeaderCellDef mat-sort-header> Target </th>
<td mat-cell *matCellDef="let element"> {{element.target}}
</td>
</ng-container>
<ng-container matColumnDef="SAP">
<th mat-header-cell *matHeaderCellDef mat-sort-header> SAP </th>
<td mat-cell *matCellDef="let element"> {{element.sap}}
</td>
</ng-container>
<ng-container matColumnDef="COLO">
<th mat-header-cell *matHeaderCellDef mat-sort-header> COLO </th>
<td mat-cell *matCellDef="let element"> {{element.colo}}
</td>
</ng-container>
<ng-container matColumnDef="Others">
<th mat-header-cell *matHeaderCellDef mat-sort-header>Others</th>
<td mat-cell *matCellDef="let element"> {{element.others}}
</td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="TargetTableColumns"></tr>
<tr mat-row *matRowDef="let row; columns: TargetTableColumns"></tr>
</table>
And my rowSpanLength function like below:
rowSpanLength(item) {
let nameArr = this.targetData.filter(i => i.name === item.name);
//return length if the item is first element in above array else 0
return nameArr[0].id === item.id ? nameArr.length : 0;
}
This function will keep rowSpan if the item/tr is first one from Group, for rest of all items the Name td will be hidden.
The result is like below which is what i wanted. got this idea from #uminder (https://stackoverflow.com/users/2358409/uminder) stackblitz

Angular material combine same column values in table and show only single value for multiple rows

I have a field called purchase_id which is the same for multiple records. Many records have the same purchase_id. Currently, I am showing the same purchase_id for multiple records, but now I want to combine the cells which have the same purchase_id and show purchase_id only once for the same records
Thanks in advance
My code
<table mat-table [dataSource]="dataSource" matSort matSortActive="serial_no" matSortDirection="desc" class="mat-elevation-z8" >
<ng-container matColumnDef="serial_no">
<th mat-header-cell *matHeaderCellDef mat-sort-header> Serial number </th>
<td mat-cell *matCellDef="let element"> {{element.serial_no}} </td>
<td mat-footer-cell *matFooterCellDef> Total </td>
</ng-container>
<ng-container matColumnDef="purchase_id">
<th mat-header-cell *matHeaderCellDef> Purchase_id </th>
<td mat-cell *matCellDef="let element"> {{element.purchase_id}} </td>
<td mat-footer-cell *matFooterCellDef> </td>
</ng-container>
<ng-container matColumnDef="product_name">
<th mat-header-cell *matHeaderCellDef mat-sort-header> Product Name </th>
<td mat-cell *matCellDef="let element"> {{element.product_name}} </td>
<td mat-footer-cell *matFooterCellDef> </td>
</ng-container>
<ng-container matColumnDef="quantity">
<th mat-header-cell *matHeaderCellDef> Quantity </th>
<td mat-cell *matCellDef="let element"> {{element.quantity}} </td>
<td mat-footer-cell *matFooterCellDef> {{totalquant}} </td>
</ng-container>
<ng-container matColumnDef="buyingprice">
<th mat-header-cell *matHeaderCellDef> Buyingprice </th>
<td mat-cell *matCellDef="let element"> {{element.buyingprice}} </td>
<td mat-footer-cell *matFooterCellDef>{{(totalPrice)}} </td>
</ng-container>
<ng-container matColumnDef="vendor_name">
<th mat-header-cell *matHeaderCellDef mat-sort-header> Vendor Name </th>
<td mat-cell *matCellDef="let element"> {{element.vendor_name}} </td>
<td mat-footer-cell *matFooterCellDef> </td>
</ng-container>
<ng-container matColumnDef="date">
<th mat-header-cell *matHeaderCellDef mat-sort-header> Date </th>
<td mat-cell *matCellDef="let element"> {{element.date}} </td>
<td mat-footer-cell *matFooterCellDef> </td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
<tr mat-footer-row *matFooterRowDef="displayedColumns; sticky: true"></tr>
</table>
<mat-paginator [pageSizeOptions]="[5, 10, 25, 100]"></mat-paginator>
I solved this problem in the open source project Koia using a RowSpanComputer class. Within summary-table.component.html, the computed row spans are then used to define the rowspan attribute of the td element.
[attr.rowspan]="rowSpans[iCol][iRow].span"
The rowspan attribute specifies the number of rows a cell should span. The RowSpanComputer class computes the rowspan for each cell out of the specified table data (array of rows). It basically loops over the rows and increments the rowspan for cells as long as their value remains unchanged. As soon as the value changes, the corresponding rowspan is reset to zero.
Please take a look at this StackBlitz

Not able to implement Sorting and Pagination in Angular 7, multiple tables

Not able to implement Sorting and Pagination in Angular 7, in mat-accordions (mat-expansion-panel) where each of them have a mat-table with independent datasources. Sorting and pagination which is pretty easy in implementation while for a single table, is giving trouble when I am trying to do it from a mat-accordion having multiple mat-expansion-panels.
I have tried this (https://stackblitz.com/edit/data-table-multiple-data-source) method, but cannot change the type of view in code, so the dropdowns have to stay.
<div class="grid-container">
<div class="grid-list">
<mat-accordion class="expand-panel">
<mat-expansion-panel>
<mat-expansion-panel-header>
<mat-panel-title>
Case Document
</mat-panel-title>
</mat-expansion-panel-header>
<button class="add-button" mat-mini-fab matTooltip="Add Document" style="float: right">
<mat-icon class="add" (click)="addPopup('documentUpload')">add</mat-icon>
</button>
<table mat-table [dataSource]="documentDataSource" matSort>
<ng-container matColumnDef="document-name">
<th class="header" mat-header-cell *matHeaderCellDef mat-sort-header>Document Name</th>
<td mat-cell *matCellDef="let document">{{document?.name}}</td>
</ng-container>
<ng-container matColumnDef="document-category">
<th class="header" mat-header-cell *matHeaderCellDef mat-sort-header>Category</th>
<td mat-cell *matCellDef="let document">{{document?.category}}</td>
</ng-container>
<ng-container matColumnDef="document-date">
<th class="header" mat-header-cell *matHeaderCellDef mat-sort-header>Date Uploaded</th>
<td mat-cell *matCellDef="let document">{{document?.createdDate}}</td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="documentTableColumns"></tr>
<tr mat-row *matRowDef="let document; columns: documentTableColumns"></tr>
</table>
<mat-paginator [pageSizeOptions]="[5, 10, 25, 100]" showFirstLastButtons></mat-paginator>
</mat-expansion-panel>
</mat-accordion>
</div>
<div class="grid-list">
<mat-accordion class="expand-panel">
<mat-expansion-panel>
<mat-expansion-panel-header>
<mat-panel-title>
Case History
</mat-panel-title>
</mat-expansion-panel-header>
<table mat-table #historySort="matSort" [dataSource]="caseHistoryDataSource"
matSort>
<ng-container matColumnDef="type">
<th class="header" mat-header-cell mat-sort-header *matHeaderCellDef>Action</th>
<td mat-cell *matCellDef="let history">{{history?.type}}</td>
</ng-container>
<ng-container matColumnDef="key">
<th class="header" mat-header-cell mat-sort-header *matHeaderCellDef>Case Property</th>
<td mat-cell *matCellDef="let history">{{history?.key}}</td>
</ng-container>
<ng-container matColumnDef="valueName">
<th class="header" mat-header-cell mat-sort-header *matHeaderCellDef>Revised Value</th>
<td mat-cell *matCellDef="let history">{{history?.valueName}}</td>
</ng-container>
<ng-container matColumnDef="oldValueName">
<th class="header" mat-header-cell mat-sort-header *matHeaderCellDef>Previous Value</th>
<td mat-cell *matCellDef="let history">{{history?.oldValueName}}</td>
</ng-container>
<ng-container matColumnDef="createdDate">
<th class="header" mat-header-cell mat-sort-header *matHeaderCellDef>Date and Time</th>
<td mat-cell *matCellDef="let history">{{history?.createdDate | date: 'short'}}</td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="historyTableColumns"></tr>
<tr mat-row *matRowDef="let history; columns: historyTableColumns"></tr>
</table>
<mat-paginator [pageSizeOptions]="[5, 10, 25, 100]" showFirstLastButtons></mat-paginator>
</mat-expansion-panel>
</mat-accordion>
</div>
<div>
And here is the .ts file implementation.
#ViewChild(MatPaginator) historyPaginator: MatPaginator;
#ViewChild(MatSort) historySort: MatSort;
#ViewChild(MatPaginator) documentPaginator: MatPaginator;
#ViewChild(MatSort) documentSort: MatSort;
async ngAfterViewInit() {
this.caseHistoryDataSource.paginator = this.historyPaginator;
this.caseHistoryDataSource.sort = this.historySort;
this.documentDataSource.paginator = this.documentPaginator;
this.documentDataSource.sort = this.documentSort;
}
The data is visible, and showing properly, but the paginator and sorting are not working.
You should bind your pagination and sort once you loaded with data like..
this.caseHistoryDataSource=new MatTableDataSource<any>(data);
this.caseHistoryDataSource.paginator = this.historyPaginator;
this.caseHistoryDataSource.sort = this.historySort;

How to add sub columns in Mat table column of angular Material table

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>

Resources