如何在Angular组件与Material Design模板间传递对象列表
Angular Material表格无法渲染接口返回的分页数据问题
我在Angular组件中实现了getReports方法,该方法订阅接口后返回包含对象列表的分页数据(控制台打印可见),希望在Material Design构建的HTML表格模板中展示每个报告的from、until、issi、status等字段,但数据似乎未正确从组件传递到HTML模板。相关代码与数据如下:
接口返回数据
{"content": [{"id": 1,"from": "2022-03-14T23:00:00","until": "2022-03-15T13:37:00","issi": "1500","format": "KML","creationDate": "2023-01-19T11:53:40.018808","status": "DOWNLOADABLE"},{"id": 2,"from": "2022-03-14T23:00:00","until": "2022-03-15T13:37:00","issi": "1500","format": "KML","creationDate": "2023-01-19T11:54:23.810516","status": "DOWNLOADABLE"},{"id": 3,"from": "2022-03-14T23:00:00","until": "2022-03-15T13:37:00","issi": "1500","format": "CSV","creationDate": "2023-01-19T11:55:24.018175","status": "DOWNLOADABLE"}],"pageable": {"sort": {"empty": false,"sorted": true,"unsorted": false},"offset": 0,"pageNumber": 0,"pageSize": 25,"unpaged": false,"paged": true},"totalPages": 1,"totalElements": 12,"last": true,"size": 25,"number": 0,"sort": {"empty": false,"sorted": true,"unsorted": false},"first": true,"numberOfElements": 12,"empty": false}
组件代码
import {Component, ViewChild, AfterViewInit, Input} from '@angular/core'; import {MatPaginator} from '@angular/material/paginator'; import {ReportInterface} from "../../types/ReportInterface"; import {MatTableDataSource} from "@angular/material/table"; import {ReportsService} from "../../services/reports.service"; import {saveAs} from "file-saver"; @Component({ selector: 'app-reports-table', templateUrl: './reports-table.component.html', styleUrls: ['./reports-table.component.scss'] }) export class ReportsTableComponent implements AfterViewInit { public displayedColumns: string[] = ['createdAt', 'from', 'until', 'devices', 'status', 'action']; @Input() data: ReportInterface[] = []; dataSource!: MatTableDataSource<any>; // @ViewChild(MatPaginator) paginator: MatPaginator; constructor(private reportsService: ReportsService) { } ngOnInit(): void { this.getReports(); } ngAfterViewInit(): void { // this.dataSource.paginator = this.paginator; } downloadReport(id: number, format: 'CSV' | 'KML') { this.reportsService.downloadReport(id).subscribe((buffer) => { const data: Blob = new Blob([buffer], { type: "text/csv;charset=utf-8" }); if (format === 'CSV') { return saveAs(data, "report-" + id + ".csv"); } return saveAs(data, "report-" + id + ".kml"); }); } getReports() { this.reportsService.getAllReports().subscribe({ next: (element:ReportInterface[]) => { this.dataSource = new MatTableDataSource(element); console.log('aco',element); }, error: (err) => { alert('Error while fetching users'); }, }); } }
HTML模板代码
<table mat-table [dataSource]="dataSource" class="reports-table"> <!-- Create at Column --> <ng-container matColumnDef="createdAt"> <th mat-header-cell *matHeaderCellDef> Created at </th> <td mat-cell *matCellDef="let element"> {{element.creationDate | date: 'd/M/yy - H:mm'}} </td> </ng-container> <!-- From Column --> <ng-container matColumnDef="from"> <th mat-header-cell *matHeaderCellDef> From </th> <td mat-cell *matCellDef="let element"> {{element.from | date: 'd/M/yy - H:mm'}} </td> </ng-container> <!-- Until Column --> <ng-container matColumnDef="until"> <th mat-header-cell *matHeaderCellDef> To </th> <td mat-cell *matCellDef="let element"> {{element.until | date: 'd/M/yy - H:mm'}} </td> </ng-container> <!-- Status Column --> <ng-container matColumnDef="status"> <th mat-header-cell *matHeaderCellDef> Status </th> <td mat-cell *matCellDef="let element"> {{element.status.toLowerCase()}} </td> </ng-container> <!-- Devices Column --> <ng-container matColumnDef="devices"> <th mat-header-cell *matHeaderCellDef> Devices </th> <td mat-cell *matCellDef="let element"> {{element.issi}} </td> </ng-container> <!-- Actions Column --> <ng-container matColumnDef="action"> <th mat-header-cell *matHeaderCellDef> Action </th> <td mat-cell *matCellDef="let element"> <button mat-button class="download-button" (click)="downloadReport(element.id, element.format)">Download in {{element.format}}</button> </td> </ng-container> <tr mat-header-row *matHeaderRowDef="displayedColumns"></tr> <tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr> <mat-paginator [pageSizeOptions]="[5, 10, 20]" showFirstLastButtons aria-label="Select page of periodic elements"> </mat-paginator> </table>
问题分析与解决方案
核心问题
接口返回的是分页结构数据,实际的报告列表存储在content字段中,但组件代码直接把整个响应对象传给了MatTableDataSource,而非提取content数组。此外还有两个次要问题:
- 组件未实现
OnInit接口,ngOnInit可能无法正常触发 - 分页器未正确绑定到数据源
修复步骤
修正接口响应处理
在getReports方法中,提取响应里的content字段作为表格数据源:getReports() { this.reportsService.getAllReports().subscribe({ next: (response) => { // 提取content数组作为数据源 this.dataSource = new MatTableDataSource(response.content); // 绑定分页器 this.dataSource.paginator = this.paginator; console.log('aco', response.content); }, error: (err) => { alert('Error while fetching reports'); }, }); }实现OnInit接口
修改组件类定义,添加OnInit接口:export class ReportsTableComponent implements OnInit, AfterViewInit { // ... 其他代码 }启用分页器绑定
取消注释@ViewChild和ngAfterViewInit中的代码:@ViewChild(MatPaginator) paginator!: MatPaginator; ngAfterViewInit(): void { if (this.dataSource) { this.dataSource.paginator = this.paginator; } }也可直接在数据加载完成后绑定分页器(如步骤1所示),避免异步加载导致的分页器未初始化问题。
可选:类型定义优化
定义分页响应类型,让代码更严谨:export interface PageResponse<T> { content: T[]; pageable: any; totalPages: number; totalElements: number; // 其他分页相关字段 }订阅时指定类型:
next: (response: PageResponse<ReportInterface>) => { // ... }
验证修复
完成修改后重新运行项目,表格将正确渲染content中的报告数据,分页器也能正常工作。
内容的提问来源于stack exchange,提问作者Aleksandar
相关产品推荐
相关产品推荐

