How to show split header in the material table having nested group of data in angular
the data source need to be an array of data you want to display. So you have to change
dataSource1 = newData;
to
dataSource1 = newData.data.summary;
You will also need to change the columns in the template since the objects are different, for example:
<td mat-cell *matCellDef="let element" class="similar-cell-width">{{ element.data[0].amount }}</td>
Displaying nested array with mat-table
If it is fixed, always 2 FOO. You can do something like this.
{{element.FooChain[0].Foo}}
{{element.FooChain[1].Foo}}
However, i'm not sure you can sort and filter by those properties in case you need it.
If the number vary, you have to implement ng-for.
<mat-cell *matCellDef="let element">
<div>
<ng-container *ngFor="let item of element?.FooChain">
<div >
<span>{{item.Foo}}</span>
</div>
</ng-container>
</div>
</mat-cell>
Trying to use Angular Material table on object that contains another object
The same idea of LotteLemmens using pipe map in your service:
this.httpClient.get(...).pipe(map(data:any[]=>{
return data.map(r=>({
brand: r.brand,
type: r.type,
value: r.value,
fields1: r.rating[0],
fields2: r.rating[1],
fields3: r.rating[2]
}))
}))
Another idea is simply use {{col.indexOf('fields')>0?element[col][+col[6]-1]:element[col]}}
(*)
<ng-container *ngFor="let col of columns" matColumnDef="{{col}}">
<mat-header-cell *matHeaderCellDef>{{ col }}</mat-header-cell>
<mat-cell *matCellDef="let element">
{{col.indexOf('fields')>=0?element[col][+col[6]-1]:element[col]}}
</mat-cell>
</ng-container>
(*) when we use over a string variable[4]
get the character in position 5th, we convert in number (adding the +
and subtract 1) -usually it's prefer our fields was fields0, fields1 and fields2 to avoid the "substract", but it is our election.
Another aproach is to have a variable columnsWihoutFields
columnsWihoutFields="brand,type,value"
And make two loops:
<!--loop over columnsWithoutFields-->
<ng-container *ngFor="let col of columnsWihoutFields" matColumnDef="{{col}}">
<mat-header-cell *matHeaderCellDef>{{ col }}</mat-header-cell>
<mat-cell *matCellDef="let element">
{{ element[col] }}
</mat-cell>
</ng-container>
<!--loops to show the fields-->
<ng-container *ngFor="let col of [1,2,3]" matColumnDef="{{'fields'+col}}">
<mat-header-cell *matHeaderCellDef>{{ 'fields'+col}}</mat-header-cell>
<mat-cell *matCellDef="let element">
{{ element.ratting[col] }}
</mat-cell>
</ng-container>
NOTE: I suppose your columns are "brand,type,value,field1,field2,field3"
Angular Material mat-table Row Grouping
A very simple answer would be to sort by the GroupID, this will put those rows together in groups. However, I'm guessing you want a header row displayed before each group.
You can provide an alternative <mat-row *matRowDef="...
that uses a where clause. This can be used to display a non-default set of columns. The where clause takes a function that returns true if that matRowDef should be used.
The data you supply to the table would then be the data rows interspersed with group rows, and the function tells one from the other. Taking Basic use of <table mat-table>
as a starter, manually add the groups and add the where clause function to app/table-basic-example.ts:
import {Component} from '@angular/core';
export interface PeriodicElement {
name: string;
position: number;
weight: number;
symbol: string;
}
export interface Group {
group: string;
}
const ELEMENT_DATA: (PeriodicElement | Group)[] = [
{group: "Group 1"},
{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'},
{group: "Group 2"},
{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'},
{group: "Group 3"},
{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;
isGroup(index, item): boolean{
return item.group;
}
}
/** Copyright 2018 Google Inc. All Rights Reserved.
Use of this source code is governed by an MIT-style license that
can be found in the LICENSE file at http://angular.io/license */
And add the groupHeader Column and the extra matRowDef to the app/table-basic-example.html:
<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">
<mat-header-cell *matHeaderCellDef> No. </mat-header-cell>
<mat-cell *matCellDef="let element"> {{element.position}} </mat-cell>
</ng-container>
<!-- Name Column -->
<ng-container matColumnDef="name">
<mat-header-cell *matHeaderCellDef> Name </mat-header-cell>
<mat-cell *matCellDef="let element"> {{element.name}} </mat-cell>
</ng-container>
<!-- Weight Column -->
<ng-container matColumnDef="weight">
<mat-header-cell *matHeaderCellDef> Weight </mat-header-cell>
<mat-cell *matCellDef="let element"> {{element.weight}} </mat-cell>
</ng-container>
<!-- Symbol Column -->
<ng-container matColumnDef="symbol">
<mat-header-cell *matHeaderCellDef> Symbol </mat-header-cell>
<mat-cell *matCellDef="let element"> {{element.symbol}} </mat-cell>
</ng-container>
<ng-container matColumnDef="groupHeader">
<mat-cell *matCellDef="let group">{{group.group}}</mat-cell>
</ng-container>
<mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
<mat-row *matRowDef="let row; columns: displayedColumns"></mat-row>
<mat-row *matRowDef="let row; columns: ['groupHeader']; when: isGroup"> </mat-row>
</mat-table>
<!-- Copyright 2018 Google Inc. All Rights Reserved.
Use of this source code is governed by an MIT-style license that
can be found in the LICENSE file at http://angular.io/license -->
Here is a finished stackblitz which groups by the element's initial letter.
And here is a far more developed stackblitz just supply the list of columns you want to group by and it will insert the group rows for you. You can also click the group rows to expand or collapse them
And finally here is a Github project that modifies a copy of the MatTableDataSource class from the material codebase. Works nicely with filter and sort, but 'competes' with the paginator as they both limit the view of records in different ways.
How to create a nested mat-table in a table with expandable rows using angular material
Note: For those who want to skip the lengthy explanation, here is the StackBlitz example.
What you actually want is to create a nested mat-table
where all the nested tables are sortable and can be filtered through as well.
Firstly, since you need to use filtering and sorting in your nested table, you need to create a new MatTableDataSource
for it. This can be done initially when you create the main dataSource
in the ngOnInit
like below.
usersData: User[] = [];
USERS.forEach(user => {
if (user.addresses && Array.isArray(user.addresses) && user.addresses.length) {
this.usersData = [...this.usersData, { ...user, addresses: new MatTableDataSource(user.addresses) }];
} else {
this.usersData = [...this.usersData, user];
}
});
this.dataSource = new MatTableDataSource(this.usersData);
From the expandable rows example in the docs, we can see how to create an expandable row. In the expandable row, we will now have a table along with the Filter
input. We will add some conditions so that the row is expandable only if there are addresses
present.
<div class="example-element-detail" *ngIf="element.addresses?.data.length"
[@detailExpand]="element == expandedElement ? 'expanded' : 'collapsed'">
<div class="inner-table mat-elevation-z8" *ngIf="expandedElement">
<mat-form-field>
<input matInput (keyup)="applyFilter($event.target.value)" placeholder="Filter">
</mat-form-field>
<table #innerTables mat-table #innerSort="matSort" [dataSource]="element.addresses" matSort>
<ng-container matColumnDef="{{innerColumn}}" *ngFor="let innerColumn of innerDisplayedColumns">
<th mat-header-cell *matHeaderCellDef mat-sort-header> {{innerColumn}} </th>
<td mat-cell *matCellDef="let element"> {{element[innerColumn]}} </td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="innerDisplayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: innerDisplayedColumns;"></tr>
</table>
</div>
</div>
Now that the row expands only if there are nested elements, we need to get rid of the hover for the users which have no addresses
Here is the CSS responsible for adding a background-color
on hover
tr.example-element-row:not(.example-expanded-row):hover {
background: #777;
}
So we just need to add the example-element-row
class to our row if the row has an address
. If it has no address, the row should not be clickable and there should not be a hover which indicates to the user that the row is in fact not clickable.
<tr mat-row *matRowDef="let element; columns: columnsToDisplay;"
[class.example-element-row]="element.addresses?.data.length"
[class.example-expanded-row]="expandedElement === element"
(click)="toggleRow(element)">
</tr>
In toggleRow
, we will define the logic for what happens when you click a row in the template. We will also implement sort
when the user clicks on the row in this function.
@ViewChildren('innerSort') innerSort: QueryList<MatSort>;
toggleRow(element: User) {
element.addresses && (element.addresses as MatTableDataSource<Address>).data.length ? (this.expandedElement = this.expandedElement === element ? null : element) : null;
this.cd.detectChanges();
this.innerTables.forEach((table, index) => (table.dataSource as MatTableDataSource<Address>).sort = this.innerSort.toArray()[index]);
}
Finally, we need to define the applyFilter
function so the nested tables can be filtered.
@ViewChildren('innerTables') innerTables: QueryList<MatTable<Address>>;
applyFilter(filterValue: string) {
this.innerTables.forEach((table, index) => (table.dataSource as MatTableDataSource<Address>).filter = filterValue.trim().toLowerCase());
}
Here is a working example on StackBlitz.
angular material mat-table: how to multiply two column values in a 3rd column
just use [(ngModel)]="element.month"
in your mat-select
<mat-select placeholder="0" [(ngModel)]="element.month">
<mat-option *ngFor="let month of months" [value]="month.value">
{{ month.viewValue }}
</mat-option>
</mat-select>
And use {{element.price*element.month}}
NOTE: You can also use a getter to get the total and put in the footer of the table
get total()
{
return this.listData.data.map(x=>x.month*x.price).reduce((a,b)=>a+b)
}
See stackblitz
Related Topics
How to Create a Curve Between Two Gradient Using CSS
Empty Vertical Space Between Columns in Bootstrap 4
What Are the Allowed Tags Inside a ≪Li≫
How to Set Default Value to the Input[Type="Date"]
Xpath to Match @Class Value and Element Value
Transform: Translate(-50%, -50%)
How to Remove a Div But Keep Its Elements
Are Empty HTML5 Data Attributes Valid
How to Change Font-Family of Drop Down's List Item
Using CSS Td Width Absolute, Position
Youtube Embedded Video: Autoplay Feature Not Working in Iphone
Font Awesome Icon Inside Text Input Element
Using HTML5, How to Use Contenteditable Fields in a Form Submission
Make an HTML Svg Object Also a Clickable Link