I'm trying to use an Angular Material table with expandable rows, to show information only if the screen width is below a particular breakpoint. I'm using an observable isHandSetPortrait$, that I'm subscribing to in my HTML, to determine whether the breakpoint has been reached.
The table has two columns (Name, and Info). Name is displayed whether isHandsetPortrait is true or false, and Info is only displayed when isHandsetPortrait$ is false. This works as expected.
In the expandable row, I have an *ngIf that uses the same observable isHandsetPortrait$, to display text when the output of isHandsetPortrait$ is true. However, this doesn't appear to be working.
<!-- *ngIf works here -->
<div *ngIf="isHandsetPortrait$ | async">ngIf works here</div>
<div class="mat-elevation-z8">
<table mat-table [dataSource]="dataSource" matSort matSortActive="priority" matSortDirection="desc"
multiTemplateDataRows>
<!-- Name Column -->
<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>
<!-- Info Column -->
<ng-container matColumnDef="info" >
<th mat-header-cell *matHeaderCellDef></th>
<td mat-cell *matCellDef="let row" class="info-cell">
Info
</td>
</ng-container>
<!-- Expanded Content Column - The detail row is made up of this one column that spans across all columns -->
<ng-container matColumnDef="expandedDetail">
<td mat-cell *matCellDef="let element" [attr.colspan]="displayedColumns.length">
<div class="expanded-content" [@detailExpand]="element == expandedElement ? 'expanded' : 'collapsed'">
Additional text....
<!-- *ngIf does not work here -->
<div *ngIf="isHandsetPortrait$ | async">ngIf does not work here</div>
</div>
</td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="getDisplayedColumns(isHandsetPortrait$ | async)"></tr>
<tr mat-row *matRowDef="let element; columns: getDisplayedColumns(isHandsetPortrait$ | async);"
class="example-element-row" [class.example-expanded-row]="expandedElement === element"
(click)="expandedElement = expandedElement === element ? null : element"></tr>
<tr mat-row *matRowDef="let row; columns: ['expandedDetail']" class="example-detail-row"></tr>
</table>
</div>
import { Component, OnInit, ViewChild } from '@angular/core';
import { MatPaginator, MatSort, MatTableDataSource } from '@angular/material';
import { animate, state, style, transition, trigger } from '@angular/animations';
import { from, Observable, of, pipe } from 'rxjs';
import { concatMap, delay, map, share } from 'rxjs/operators';
import { BreakpointObserver, Breakpoints } from '@angular/cdk/layout';
/**
* @title Table with expandable rows
*/
@Component({
selector: 'table-expandable-rows-example',
styleUrls: ['table-expandable-rows-example.css'],
templateUrl: 'table-expandable-rows-example.html',
animations: [
trigger('detailExpand', [
state('collapsed', style({ height: '0px', minHeight: '0' })),
state('expanded', style({ height: '*' })),
transition('expanded <=> collapsed', animate('225ms cubic-bezier(0.4, 0.0, 0.2, 1)'))
]),
]
})
export class TableExpandableRowsExample {
public isHandsetPortrait$: Observable<boolean> = this.breakpointObserver.observe(Breakpoints.HandsetPortrait)
.pipe(
map(orientationState => orientationState.matches),
share()
);
private chatRequests = [
{
name: 'John Wayne'
},
{
name: 'Oscar Wilde'
},
{
name: 'Eric Cantona'
}
];
dataSource = new MatTableDataSource(this.chatRequests);
displayedColumns: { def: string, isMobile: boolean }[] = [
{
def: 'name',
isMobile: true
},
{
def: 'info',
isMobile: false
}
];
constructor(private breakpointObserver: BreakpointObserver) { }
public getDisplayedColumns(isHandsetPortrait: boolean) {
return this.displayedColumns
.filter(cd => !isHandsetPortrait || cd.isMobile)
.map(cd => cd.def);
}
}
I've put together a StackBlitz project that should highlight the issue I'm having.
The *ngIf works outside of the table (Line 2 of the html template), but does not work inside the table (Line 28 of the html template). How can I make the second *ngIf work?
you have to use shareReplay to make it works, using share nothing will happen for the second subscriber
public isHandsetPortrait$: Observable<boolean> = this.breakpointObserver.observe(Breakpoints.HandsetPortrait)
.pipe(
map(orientationState => orientationState.matches),
shareReplay(1) // here
);
https://stackblitz.com/edit/angular-ml4vym-71mba5
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With