You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

  1. Duplicate Template Reference Variables: If both tables use the same #table variable, Angular can’t distinguish between them, leading to the second table picking up the first’s data source.
  2. 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.
  3. Shared Data Source Instances: Reusing the same MatTableDataSource (or MdTableDataSource) 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 newer mat- prefix.
  • View Initialization: Inactive tabs don’t render their content by default, so we use setTimeout to wait for the DOM to load before calling renderRows().
  • Unique References: Never reuse template variables or data source instances across tables—this is the most common cause of this issue.

内容的提问来源于stack exchange,提问作者chethu

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.25 07:18:05