Angular 4单模板多Angular Material表格实现及数据源问题求助
Fixing Angular Material Table Data Source Issues in Tabs (Angular 4)
Hey there! Let's dig into this issue you're having with Angular Material tables inside tabs in Angular 4. It’s a common gotcha with tabbed content and view initialization in older Angular versions, so let’s break down the fixes step by step.
Common Causes of the Problem
- Duplicate Template Reference Variables: If both tables use the same
#tablevariable, Angular can’t distinguish between them, leading to the second table picking up the first’s data source. - Lazy Tab Initialization: In Angular 4’s Angular Material (version 2.x, using
md-prefixes), inactive tabs don’t fully render their DOM content by default. When you switch to the second tab, the table might not initialize its data source properly. - Shared Data Source Instances: Reusing the same
MatTableDataSource(orMdTableDataSource) for both tables will obviously cause conflicts.
Step-by-Step Solution
1. Use Unique Template Variables for Each Table
Make sure every table has its own distinct template reference so Angular can target them individually:
<md-tab-group (selectedIndexChange)="onTabSwitched($event)"> <!-- First Tab & Table --> <md-tab label="First Tab"> <table md-table #firstTable [dataSource]="firstTabDataSource"> <!-- Column Definitions --> <ng-container mdColumnDef="id"> <th md-header-cell *mdHeaderCellDef> ID </th> <td md-cell *mdCellDef="let item"> {{item.id}} </td> </ng-container> <ng-container mdColumnDef="name"> <th md-header-cell *mdHeaderCellDef> Name </th> <td md-cell *mdCellDef="let item"> {{item.name}} </td> </ng-container> <tr md-header-row *mdHeaderRowDef="['id', 'name']"></tr> <tr md-row *mdRowDef="let row; columns: ['id', 'name']"></tr> </table> </md-tab> <!-- Second Tab & Table --> <md-tab label="Second Tab"> <table md-table #secondTable [dataSource]="secondTabDataSource"> <!-- Column Definitions (can match or differ from first table) --> <ng-container mdColumnDef="id"> <th md-header-cell *mdHeaderCellDef> ID </th> <td md-cell *mdCellDef="let item"> {{item.id}} </td> </ng-container> <ng-container mdColumnDef="name"> <th md-header-cell *mdHeaderCellDef> Name </th> <td md-cell *mdCellDef="let item"> {{item.name}} </td> </ng-container> <tr md-header-row *mdHeaderRowDef="['id', 'name']"></tr> <tr md-row *mdRowDef="let row; columns: ['id', 'name']"></tr> </table> </md-tab> </md-tab-group>
2. Create Separate Data Source Instances
In your component, initialize unique MdTableDataSource instances for each table (note: Angular 4 uses Md prefixes instead of Mat for Material components):
import { Component, ViewChild, OnInit } from '@angular/core'; import { MdTableDataSource } from '@angular/material'; // Define your data interface interface TableItem { id: number; name: string; } @Component({ selector: 'app-tabbed-tables', templateUrl: './tabbed-tables.component.html', }) export class TabbedTablesComponent implements OnInit { // Unique data sources for each table firstTabDataSource = new MdTableDataSource<TableItem>([]); secondTabDataSource = new MdTableDataSource<TableItem>([]); // Reference each table using its unique template variable @ViewChild('firstTable') firstTable; @ViewChild('secondTable') secondTable; ngOnInit() { // Initialize first tab data this.firstTabDataSource.data = [ { id: 1, name: 'First Tab Item 1' }, { id: 2, name: 'First Tab Item 2' } ]; // Initialize second tab data (this won't render until the tab is active) this.secondTabDataSource.data = [ { id: 1, name: 'Second Tab Item 1' }, { id: 2, name: 'Second Tab Item 2' } ]; } // Triggered when the user switches tabs onTabSwitched(event) { // If switching to the second tab (index 1), force the table to render rows if (event.index === 1) { // Use setTimeout to ensure the DOM has loaded before rendering setTimeout(() => { this.secondTable.renderRows(); }); } } }
3. Handle Asynchronous Data Loading
If your data comes from an API, make sure to update the data source and trigger a render once the data is available:
loadSecondTabData() { this.yourDataService.getSecondTabData().subscribe( (data: TableItem[]) => { this.secondTabDataSource.data = data; // If the table is already rendered, force a refresh if (this.secondTable) { this.secondTable.renderRows(); } }, (error) => console.error('Error loading data:', error) ); } // Update the tab switch handler to load data when the tab is first opened onTabSwitched(event) { if (event.index === 1) { this.loadSecondTabData(); setTimeout(() => { this.secondTable.renderRows(); }); } }
Key Notes for Angular 4
- Prefixes: Angular 4 uses
md-for Material components (e.g.,md-tab-group,md-table) instead of the newermat-prefix. - View Initialization: Inactive tabs don’t render their content by default, so we use
setTimeoutto wait for the DOM to load before callingrenderRows(). - Unique References: Never reuse template variables or data source instances across tables—this is the most common cause of this issue.
内容的提问来源于stack exchange,提问作者chethu
相关产品推荐
相关产品推荐

