Reputation: 33
I am using the latest Angular version in my project. In my component I have a Mat-Tab-Group with a Mat-Tab. Inside this tab I want to display a table component that I have created by myself. This component is able to show a mat-table content. This component is working and rendering correctly, when using outside of the Mat-Tab! When placing it inside you can see the issue clearl when setting the animationDuration to a larger value: Switching to the second tab where my table component is inside, the table rows are not being rendered. When switching back to another tab, the rows appear while the tab is animating to the other tab. When looking at the html in the console, you can see that the table rows exist and do have values inside them (picture below).
Here you can see the code: Component with Mat-Tab:
<mat-tab-group animationDuration="0" mat-stretch-tabs="false" mat-align-tabs="start" (animationDone)="onChangeTabs($event)">
<mat-tab>CONTENT 1</mat-tab>
<mat-tab label="Mitglieder">
<app-overview #members TABLE_NAME="Mitglieder" [DATA_SOURCE]="dataSource" [DISPLAYED_COLUMNS]="displayedColumns" [SHOW_FILTER_MENU]="false" [SHOW_MORE_MENU]="false" #sort="matSort" matSort>
<ng-container matColumnDef="firstName">
<th mat-header-cell *matHeaderCellDef mat-sort-header> Vorname </th>
<td mat-cell *matCellDef="let element"> {{element.firstName}} </td>
</ng-container>
<ng-container matColumnDef="lastName">
<th mat-header-cell *matHeaderCellDef mat-sort-header> Nachname </th>
<td mat-cell *matCellDef="let element"> {{element.lastName}} </td>
</ng-container>
<ng-container matColumnDef="memberType">
<th mat-header-cell *matHeaderCellDef mat-sort-header> Typ </th>
<td mat-cell *matCellDef="let element"> {{element.memberType}} </td>
</ng-container>
<ng-container matColumnDef="clubName">
<th mat-header-cell *matHeaderCellDef mat-sort-header> Verein </th>
<td mat-cell *matCellDef="let element"> {{element.clubName}} </td>
</ng-container>
<ng-container matColumnDef="federalState">
<th mat-header-cell *matHeaderCellDef mat-sort-header> Bundesland </th>
<td mat-cell *matCellDef="let element"> {{element.federalState}} </td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="displayedColumns; sticky: true"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns;" (dblclick)="onNavigateMember(row)" appHighlight></tr>
</app-overview>
</mat-tab>
</mat-tab-group>
app-overview component html:
<div class="wrapper">
<mat-toolbar>
<span>{{TABLE_NAME}}</span>
<!--
<mat-form-field class="filter-style">
<mat-label>Suche ...</mat-label>
<input matInput class="filter-input-style" (keyup)="applyFilter($event)" #input autofocus>
</mat-form-field>
-->
<span class="example-spacer"></span>
<div class="searchBox">
<input class="searchInput"type="text" name="" placeholder="Suche ..." (keyup)="applyFilter($event)" #input autofocus>
<button mat-icon-button >
<mat-icon>search</mat-icon>
</button>
</div>
<button *ngIf="SHOW_FILTER_MENU" mat-icon-button (click)="openFilterPopUp()">
<mat-icon>filter_alt</mat-icon>
</button>
<button *ngIf="SHOW_MORE_MENU" mat-icon-button (click)="openMoreMenu()">
<mat-icon>more_vert</mat-icon>
</button>
</mat-toolbar>
<mat-divider></mat-divider>
<div class="table-container">
@if (isLoadingResults) {
<div class="example-loading-shade">
@if (isLoadingResults) {
<mat-spinner></mat-spinner>
}
</div>
}
<table mat-table [dataSource]="DATA_SOURCE" >
<ng-container matColumnDef="action" sticky>
<th mat-header-cell *matHeaderCellDef></th>
<td mat-cell *matCellDef="let element"> <button mat-icon-button (click)="onNavigate(element)"><mat-icon>chevron_right</mat-icon></button> </td>
</ng-container>
<ng-content></ng-content>
<tr class="mat-row" *matNoDataRow>
<td class="mat-cell" colspan="4" style="padding-left: 12px; padding-top: 12px; padding-bottom: 12px;">Keine Daten zur Anzeige vorhanden</td>
</tr>
</table>
</div>
<div class="footer">
<mat-paginator [pageSizeOptions]="[15, 20, 50, 100]" [pageSize]="PAGE_SIZE" [showFirstLastButtons]="SHOW_FIRST_LAST_BUTTONS"></mat-paginator>
</div>
</div>
app-overview ts:
import { AfterContentInit, AfterViewInit, ChangeDetectorRef, Component, ContentChild, ContentChildren, EventEmitter, Input, Output, QueryList, ViewChild } from '@angular/core';
import { MatButtonModule } from '@angular/material/button';
import { MatCardModule } from '@angular/material/card';
import { MatIconModule } from '@angular/material/icon';
import { MatPaginator, MatPaginatorModule } from '@angular/material/paginator';
import { MatSortModule } from '@angular/material/sort';
import { MatColumnDef, MatHeaderRowDef, MatNoDataRow, MatRowDef, MatTable, MatTableDataSource, MatTableModule } from '@angular/material/table';
import { MatToolbarModule } from '@angular/material/toolbar';
import {MatProgressSpinnerModule} from '@angular/material/progress-spinner';
import { CommonModule } from '@angular/common';
import { MatFormFieldModule } from '@angular/material/form-field';
import { MatInputModule } from '@angular/material/input';
import { MatDividerModule } from '@angular/material/divider';
@Component({
selector: 'app-overview',
standalone: true,
imports: [CommonModule, MatTableModule, MatSortModule, MatPaginatorModule, MatToolbarModule, MatButtonModule, MatIconModule, MatCardModule, MatProgressSpinnerModule, MatFormFieldModule, MatInputModule, MatDividerModule],
templateUrl: './overview.component.html',
styleUrl: './overview.component.css'
})
export class OverviewComponent<T> implements AfterContentInit, AfterViewInit {
@Input() DISPLAYED_COLUMNS: string[] = [];
@Input() DATA_SOURCE!: MatTableDataSource<T>;
@Input() TABLE_NAME!: String;
@Input() PAGE_SIZE: number = 20;
@Input() SHOW_FIRST_LAST_BUTTONS: boolean = true;
@Input() SHOW_MORE_MENU: boolean = true;
@Input() SHOW_FILTER_MENU: boolean = true;
@Output() reloadEvent = new EventEmitter();
@Output() navigateEvent = new EventEmitter();
@ViewChild(MatPaginator) paginator!: MatPaginator;
@ViewChild(MatTable, {static: true}) table!: MatTable<T>;
@ContentChildren(MatHeaderRowDef) headerRowDefs!: QueryList<MatHeaderRowDef>;
@ContentChildren(MatRowDef) rowDefs!: QueryList<MatRowDef<T>>;
@ContentChildren(MatColumnDef) columnDefs!: QueryList<MatColumnDef>;
@ContentChild(MatNoDataRow) noDataRow!: MatNoDataRow;
isLoadingResults: boolean = false;
constructor(private cd: ChangeDetectorRef){ }
ngAfterContentInit() {
this.columnDefs.forEach(columnDef => this.table.addColumnDef(columnDef));
this.rowDefs.forEach(rowDef => this.table.addRowDef(rowDef));
this.headerRowDefs.forEach(headerRowDef => this.table.addHeaderRowDef(headerRowDef));
this.table.setNoDataRow(this.noDataRow);
}
ngAfterViewInit(): void {
this.paginator._intl.firstPageLabel = 'Erste Seite';
this.paginator._intl.lastPageLabel = 'Letzte Seite';
this.paginator._intl.itemsPerPageLabel = 'Elemente pro Seite';
this.paginator._intl.nextPageLabel = 'Nächste Seite';
this.paginator._intl.previousPageLabel = 'Vorherige Seite';
this.paginator._intl.getRangeLabel = matRangeLabelIntl;
this.DATA_SOURCE.paginator = this.paginator;
}
public setIsLoadingResults(isLoading: boolean) {
this.isLoadingResults = isLoading;
this.cd.detectChanges();
}
openFilterPopUp() {
this.reload();
}
openMoreMenu() {
}
applyFilter(event: Event) {
const filterValue = (event.target as HTMLInputElement).value;
this.DATA_SOURCE.filter = filterValue.trim().toLowerCase();
}
reload() {
this.reloadEvent.emit();
}
onNavigate(element: any) {
this.navigateEvent.emit(element);
}
}
const matRangeLabelIntl = (page: number, pageSize: number, length: number) => {
if (length === 0) {
return 'Seite 1 von 1';
}
const amountPages = Math.ceil(length / pageSize);
return `Seite ${page + 1} - ${amountPages} von ${length}`;
}
app-overview css:
.wrapper {
width: 100%;
height: 100%;
overflow: hidden;
}
.table-container {
width: 100%;
height: calc(100% - 200px);
overflow-y: scroll;
}
.footer {
position: fixed;
left: 0;
bottom: 0;
width: 100%;
color: white;
text-align: center;
}
table {
width: 100%;
}
.filter-style {
width: 500px;
margin-left: 48px;
margin-top: 8pxs;
}
.filter-input-style {
background-color: transparent;
}
.searchBox {
margin-left: 48px;
position: relative;
background: #ececec;
height: 40px;
border-radius: 40px;
padding: 10px;
}
.searchBox:hover > .searchInput {
width: 240px;
padding: 0 6px;
}
.searchBox:hover > .searchButton {
background: white;
color : #2f3640;
}
.searchInput {
border:none;
background: none;
outline:none;
float:left;
padding: 0;
color: rgb(0, 0, 0);
font-size: 16px;
transition: 0.4s;
line-height: 40px;
width: 100px;
}
/* Active state */
.search-bar input:focus + .search-btn,
.search-bar input:valid + .search-btn {
background: #2762f3;
border-radius: 0 0.375em 0.375em 0;
transform: scale(1);
}
.search-bar input:focus + .search-btn:before,
.search-bar input:focus + .search-btn:after,
.search-bar input:valid + .search-btn:before,
.search-bar input:valid + .search-btn:after {
opacity: 1;
}
.search-bar input:focus + .search-btn:hover,
.search-bar input:valid + .search-btn:hover,
.search-bar input:valid:not(:focus) + .search-btn:focus {
background: #0c48db;
}
.search-bar input:focus + .search-btn:active,
.search-bar input:valid + .search-btn:active {
transform: translateY(1px);
}
.example-loading-shade {
position: absolute;
top: 0;
left: 0;
bottom: 56px;
right: 0;
background: rgba(0, 0, 0, 0.15);
z-index: 1;
display: flex;
align-items: center;
justify-content: center;
}
.example-rate-limit-reached {
max-width: 360px;
text-align: center;
}
/* Column Widths */
.mat-column-number,
.mat-column-state {
max-width: 64px;
}
.mat-column-created {
max-width: 124px;
}
.example-spacer {
flex: 1 1 auto;
}
.mat-toolbar {
background-color: white;
}
.example-loading-shade {
position: absolute;
top: 0;
left: 0;
bottom: 56px;
right: 0;
background: rgba(0, 0, 0, 0.15);
z-index: 1;
display: flex;
align-items: center;
justify-content: center;
}
.mat-mdc-row .mat-mdc-cell {
border-bottom: 1px solid transparent;
border-top: 1px solid transparent;
cursor: pointer;
}
.mat-mdc-row:hover .mat-mdc-cell {
border-color: currentColor;
}
I was searching for this issue but couldn't find anything related. Do you know more about this issue? Is it an known issue or a new issue for the latest version of Angular?
Upvotes: 0
Views: 677