基于Angular 4与Angular Material实现动态数据可展开表格行(API获取数据)
Got it, let's walk through building an expandable table with dynamic, API-fetched data in Angular 4 using Angular Material. I've tackled this exact scenario before, so here's a practical, step-by-step solution that works:
1. First, Set Up Dependencies
Angular 4 pairs with Angular Material 2.x (beta versions), so make sure you install the right packages:
npm install @angular/material@2.0.0-beta.12 @angular/cdk@2.0.0-beta.12 --save npm install @angular/animations@4.4.7 --save
Then, import the required modules in your app.module.ts (or a shared module):
import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; import { MatTableModule, MatExpansionModule, MatProgressSpinnerModule } from '@angular/material'; import { HttpClientModule } from '@angular/common/http'; @NgModule({ imports: [ // ... other imports BrowserAnimationsModule, HttpClientModule, MatTableModule, MatExpansionModule, MatProgressSpinnerModule ] }) export class AppModule { }
2. Component Template (HTML)
We'll create a table where clicking a main row toggles an expanded section with additional details. Since data is dynamic, we'll bind columns dynamically too.
<div class="table-container" *ngIf="!isLoading; else loading"> <mat-table [dataSource]="dataSource"> <!-- Dynamic Columns --> <ng-container *ngFor="let column of displayedColumns" [matColumnDef]="column"> <mat-header-cell *matHeaderCellDef> {{ column | titlecase }} </mat-header-cell> <mat-cell *matCellDef="let element"> {{ element[column] }} </mat-cell> </ng-container> <!-- Expandable Row Column --> <ng-container matColumnDef="expandedDetail"> <mat-cell *matCellDef="let element" [attr.colspan]="displayedColumns.length"> <div class="expanded-content" *ngIf="expandedElement === element"> <!-- Customize this section with your dynamic detail data --> <h4>Details</h4> <pre>{{ element.details | json }}</pre> </div> </mat-cell> </ng-container> <!-- Main Row --> <mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row> <mat-row *matRowDef="let row; columns: displayedColumns;" class="clickable-row" (click)="expandedElement = expandedElement === row ? null : row"></mat-row> <!-- Expandable Row --> <mat-row *matRowDef="let row; columns: ['expandedDetail']" class="expanded-row"></mat-row> </mat-table> </div> <ng-template #loading> <div class="loading-spinner"> <mat-spinner diameter="50"></mat-spinner> </div> </ng-template>
3. Component Logic (TypeScript)
We'll fetch data from an API, handle dynamic columns, and manage the expanded row state.
import { Component, OnInit } from '@angular/core'; import { HttpClient } from '@angular/common/http'; // Define an interface for your API data (adjust based on your actual response) interface Record { id: number; name: string; // Add other dynamic fields as needed details: { [key: string]: any }; // For the expandable detail content } @Component({ selector: 'app-expandable-table', templateUrl: './expandable-table.component.html', styleUrls: ['./expandable-table.component.css'] }) export class ExpandableTableComponent implements OnInit { dataSource: Record[] = []; displayedColumns: string[] = []; expandedElement: Record | null = null; isLoading = true; constructor(private http: HttpClient) { } ngOnInit(): void { this.fetchDataFromAPI(); } fetchDataFromAPI(): void { // Replace with your actual API endpoint this.http.get<Record[]>('https://your-api-endpoint.com/data') .subscribe({ next: (data) => { this.dataSource = data; // Extract dynamic column names (exclude 'details' since it's for expansion) if (data.length > 0) { this.displayedColumns = Object.keys(data[0]).filter(key => key !== 'details'); } this.isLoading = false; }, error: (err) => { console.error('Failed to fetch data:', err); this.isLoading = false; } }); } }
4. Add Some Basic Styling (CSS)
Make the table look clean and the expandable section distinguishable:
.table-container { margin: 20px; overflow-x: auto; } .clickable-row { cursor: pointer; } .clickable-row:hover { background-color: #f5f5f5; } .expanded-row { background-color: #fafafa; } .expanded-content { padding: 16px; border-top: 1px solid #eee; } .loading-spinner { display: flex; justify-content: center; margin: 40px; }
Key Notes for Dynamic Data
- Dynamic Columns: We extract column names from the first data object using
Object.keys()—this works if all your records have the same structure (which they usually do from APIs). - Expandable Content: The
detailsfield in theRecordinterface holds the data you want to show when expanding a row. Adjust this to match your API's response structure. - State Management: The
expandedElementvariable tracks which row is currently expanded—clicking the same row collapses it.
This setup will fetch your data dynamically, render a table with expandable rows, and handle loading states gracefully. Let me know if you need to tweak any part for your specific API response!
内容的提问来源于stack exchange,提问作者raghu babu

