如何从两个API取数并在Angular Material表格中关联显示用户名
解决Angular Material表格关联Posts和Users API显示用户名的问题
问题概述
现有Posts和Users两个API,通过userId字段关联,需要实现类似SQL内连接的效果,在Angular Material表格中显示Posts数据及对应的用户名,但目前无法正常显示username字段。
问题分析
- 接口定义存在错误:
Users接口中list的类型应为UsersList[]而非List[]; - 组件未同时获取两个API的数据,也未执行数据关联逻辑;
- 数据源赋值逻辑混乱,未将关联后的数据传入表格;
- Posts的
userId为字符串类型,Users的userId为数字类型,存在类型不匹配,需转换处理。
解决方案
1. 修复TypeScript接口定义
修正Users接口的类型错误:
import { UsersList} from "./UsersList" export interface Users{ list: UsersList[] // 将List[]改为UsersList[] count: number success: boolean }
建议统一userId类型,将PostsList的userId改为数字类型(或在关联时做类型转换):
export interface PostsList { id: number title: string body: string userId: number // 与UsersList的userId类型统一 }
2. 并行请求API并关联数据
使用RxJS的forkJoin同时请求两个API,获取数据后完成类似内连接的关联操作:
组件代码修改
import { forkJoin } from 'rxjs'; import { MatTableDataSource } from '@angular/material/table'; import { Posts } from './path-to-posts-interface'; import { Users } from './path-to-users-interface'; export class PostsComponent implements OnInit{ displayedColumns: string[] = ['id', 'title', 'body', 'userId', 'username']; dataSource!: MatTableDataSource<any>; private postsList: any[] = []; private usersList: any[] = []; constructor(private myService: MyService){ } ngOnInit(): void { this.loadJoinedData(); } loadJoinedData(): void { forkJoin([ this.myService.getPosts(), this.myService.getUsers() ]).subscribe(([postsRes, usersRes]) => { this.postsList = postsRes.list; this.usersList = usersRes.list; // 关联数据,匹配对应的用户名 const joinedData = this.postsList.map(post => { // 处理userId类型转换(如果未修改接口类型的话) const user = this.usersList.find(u => u.userId === parseInt(post.userId)); return { ...post, username: user ? user.username : 'Unknown' }; }); this.dataSource = new MatTableDataSource(joinedData); }); } }
3. 修正表格模板绑定
修改模板的数据源绑定,确保使用关联后的dataSource:
<table mat-table [dataSource]="dataSource" class="mat-elevation-z8"> <ng-container matColumnDef="id"> <th mat-header-cell *matHeaderCellDef> ID</th> <td mat-cell *matCellDef="let element">{{element.id}}</td> </ng-container> <ng-container matColumnDef="title"> <th mat-header-cell *matHeaderCellDef> 标题</th> <td mat-cell *matCellDef="let element">{{element.title}}</td> </ng-container> <ng-container matColumnDef="body"> <th mat-header-cell *matHeaderCellDef> 内容</th> <td mat-cell *matCellDef="let element">{{element.body}}</td> </ng-container> <ng-container matColumnDef="userId"> <th mat-header-cell *matHeaderCellDef> 用户ID </th> <td mat-cell *matCellDef="let element">{{element.userId}}</td> </ng-container> <ng-container matColumnDef="username"> <th mat-header-cell *matHeaderCellDef> 用户名 </th> <td mat-cell *matCellDef="let element">{{element.username}}</td> </ng-container> <tr mat-header-row *matHeaderRowDef="displayedColumns"></tr> <tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr> </table>
4. 可选:添加类型安全的关联接口
为保证类型安全,可创建新接口定义关联后的数据结构:
import { PostsList } from "./PostsList"; export interface PostWithUser extends PostsList { username: string; }
然后在组件中替换数据源类型:
dataSource!: MatTableDataSource<PostWithUser>; // 关联数据时指定类型 const joinedData: PostWithUser[] = this.postsList.map(post => { const user = this.usersList.find(u => u.userId === parseInt(post.userId)); return { ...post, username: user ? user.username : 'Unknown' }; });
内容的提问来源于stack exchange,提问作者Kareem
相关产品推荐
相关产品推荐

