英文:
How to get data from 2 api and view data in angular material table?
问题
You can display the username
from another API in your Angular component by performing a join-like operation on the data from both APIs. Since Angular operates on the client side, you'll need to manipulate the data in your component to achieve this.
Here's a high-level overview of how you can do it:
-
Fetch the data from both APIs using your service methods,
getPosts()
andgetUsers()
. -
In your component, subscribe to both API calls and store their responses in variables.
-
Use JavaScript array methods like
map()
orforEach()
to iterate through the data from the "users" API and find the corresponding username for each item in the "posts" API based on theuserId
. -
Update the data structure of your "posts" API to include the
username
property obtained from the "users" API.
Here's an example of how you can modify your component to achieve this:
import { Component, OnInit } from '@angular/core';
import { MyService } from './my-service'; // Import your service
@Component({
selector: 'app-users',
templateUrl: './users.component.html',
styleUrls: ['./users.component.css']
})
export class UsersComponent implements OnInit {
displayedColumns: string[] = ['id', 'title', 'body', 'userId', 'username'];
posts: any; // Rename users to posts
users: any;
constructor(private myService: MyService) { }
ngOnInit(): void {
this.onGetPostsAndUsers(); // Call the combined method
}
onGetPostsAndUsers(): void {
// Combine the data fetching
this.myService.getPosts().subscribe(
(postsResponse) => {
this.posts = postsResponse.list; // Store posts data
this.myService.getUsers().subscribe(
(usersResponse) => {
this.users = usersResponse.list; // Store users data
// Perform the join operation
this.posts.forEach((post: any) => {
const user = this.users.find((u: any) => u.userId === post.userId);
if (user) {
post.username = user.username;
}
});
}
);
}
);
}
}
With this code, after fetching data from both APIs and joining them based on the userId
, you should have the username
property in your "posts" data, and you can display it in your Material table as you've shown in your HTML template.
英文:
Ihave 2 api ( users and category ), and I have relationship between this api in category id, how can I make join this api like inner join in sql.
My Code :
- frist API ( name in posts ):
{
"list": [
{
"id": 1,
"title": "samsung",
"body": "samsung is ......",
"userId": "1"
},
{
"id": 2,
"title": "google",
"body": "google is ......",
"userId": "1"
},
{
"id": 1,
"title": "yahoo",
"body": "yahoo is ......",
"userId": "2"
}
],
"count": 3,
"success": true
}
- second API ( name in users):
{
"list": [
{
"userId": 1,
"username": "Michil"
},
{
"userId": 2,
"username": "Alix"
},
{
"userId": 3,
"username": "Jon"
}
],
"count": 3,
"success": true
}
- and I created 2 interfaces for this API like this:
import { PostsList } from "./PostsList "
export interface Posts{
list: PostsList[]
count: number
success: boolean
}
export interface PostsList {
id: number
title: string
body: string
userId: string
}
import { UsersList} from "./UsersList"
export interface Users{
list: List[]
count: number
success: boolean
}
export interface UsersList{
userId: number
username: string
}
- and I created a service to get data from the APIS URL like this:
getPosts(): Observable<Posts>{
return this.http.get<Posts>(`https://api.api.com/post/list`).pipe(
tap(posts=> console.log(posts)),
);
}
getUsers(): Observable<Users>{
return this.http.get<Users>(`https://api.api.com/users/list`).pipe(
tap(users => console.log(users)),
);
}
- and I called this service in my component.ts like this:
export class UsersComponent implements OnInit{
displayedColumns: string[] = ['id', 'title', 'body', 'userId', 'username'];
users:any;
constructor(private myService: MyService){ }
ngOnInit(): void {
this.onGetUsers();
}
onGetPosts(): void{
this.myService.getPosts().subscribe(
(response => {
this.users = new MatTableDataSource<Posts>(response);
})
);
}
onGetUsers(): void{
this.myService.getUsers().subscribe(
(response => {
this.Posts = new MatTableDataSource<Posts>(response);
this.Users = new MatTableDataSource<Users>(response);
})
);
}
- and view this data in the material table like this:
<table mat-table [dataSource]="users" class="mat-elevation-z8">
Position Column
<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> title</th>
<td mat-cell *matCellDef="let element"> {{element.title}} </td>
</ng-container>
<ng-container matColumnDef="body">
<th mat-header-cell *matHeaderCellDef> body</th>
<td mat-cell *matCellDef="let element"> {{element.body}} </td>
</ng-container>
<ng-container matColumnDef="userId">
<th mat-header-cell *matHeaderCellDef> userId </th>
<td mat-cell *matCellDef="let element"> {{element.userId}} </td>
</ng-container>
<ng-container matColumnDef="username">
<th mat-header-cell *matHeaderCellDef> username </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>
How can I display username from another api ?
答案1
得分: 1
你可以创建一个新的接口,将PostsList
和UsersList
两者结合在一起,如下所示:
export interface TableView {
post: PostsList;
user: UsersList;
}
之后,你需要在这个视图中填充数据。唯一的问题是它依赖于两个 API,因此我们需要来自两个 API 的结果,然后可以尝试合并这两个 API 的数据。一个简单的方法是使用Promise.all来实现这一点。
export class UsersComponent implements OnInit {
displayedColumns: string[] = ['id', 'title', 'body', 'userId', 'username'];
// 表格的数据源
dataSource: MatTableDataSource<TableView> =
new MatTableDataSource<TableView>();
constructor(private myService: UsersService) {}
ngOnInit(): void {
// 用于获取两个 API 结果的 Promise 数组
let dataPromise: Array<Promise<any>> = [];
// 将 Observables 转换为 Promise 并添加到这个数组中
dataPromise.push(this.myService.getPosts().toPromise());
dataPromise.push(this.myService.getUsers().toPromise());
// 在获得两个 Promise 的结果后进行数据操作
Promise.all(dataPromise).then((responseList) => {
// responseList 中的第一项来自 getPosts
let posts: Posts = responseList[0];
// responseList 中的第二项来自 getUsers
let users: Users = responseList[1];
// 用于存储数据的临时数组
let tableData: Array<TableView> = [];
posts.list.forEach((x) => {
tableData.push({
post: x,
user: users.list.filter((y) => y.userId.toString() === x.userId)[0], // 获取与此 userId 对应的用户
});
});
this.dataSource = new MatTableDataSource<TableView>(tableData);
});
}
}
现在修改你的 HTML 以使用新的接口。
<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.post.id }}</td>
</ng-container>
<ng-container matColumnDef="title">
<th mat-header-cell *matHeaderCellDef>title</th>
<td mat-cell *matCellDef="let element">{{ element.post.title }}</td>
</ng-container>
<ng-container matColumnDef="body">
<th mat-header-cell *matHeaderCellDef>body</th>
<td mat-cell *matCellDef="let element">{{ element.post.body }}</td>
</ng-container>
<ng-container matColumnDef="userId">
<th mat-header-cell *matHeaderCellDef>userId</th>
<td mat-cell *matCellDef="let element">{{ element.user.userId }}</td>
</ng-container>
<ng-container matColumnDef="username">
<th mat-header-cell *matHeaderCellDef>username</th>
<td mat-cell *matCellDef="let element">{{ element.user.username }}</td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns"></tr>
</table>
演示:https://stackblitz.com/edit/angular-tm2met?file=src%2Fusers%2Fusers.component.ts
英文:
You can create a new interface which combines both PostsList
and UsersList
like:
export interface TableView {
post: PostsList;
user: UsersList;
}
After that, you need to populate data in this view. The only problem is that it depends on both API's, therefore we need result from both API's and after that, we can try to join data from both API's. One easy way to do this is through Promise.all.
export class UsersComponent implements OnInit {
displayedColumns: string[] = ['id', 'title', 'body', 'userId', 'username'];
// Datasource for table
dataSource: MatTableDataSource<TableView> =
new MatTableDataSource<TableView>();
constructor(private myService: UsersService) {}
ngOnInit(): void {
// Promise for getting results of both API's
let dataPromise: Array<Promise<any>> = [];
// Convert observables and push to this promise
dataPromise.push(this.myService.getPosts().toPromise());
dataPromise.push(this.myService.getUsers().toPromise());
// Do data manipulation after we get results from both Promises
Promise.all(dataPromise).then((responseList) => {
// First item in responseList is from getPosts
let posts: Posts = responseList[0];
// Second item in responseList is from getUsers
let users: Users = responseList[1];
// Temporary array for storing data
let tableData: Array<TableView> = [];
posts.list.forEach((x) => {
tableData.push({
post: x,
user: users.list.filter((y) => y.userId.toString() === x.userId)[0], // get the user for this userId
});
});
this.dataSource = new MatTableDataSource<TableView>(tableData);
});
}
}
Now change your HTML to use new interface.
<table mat-table [dataSource]="dataSource" class="mat-elevation-z8">
Position Column
<ng-container matColumnDef="id">
<th mat-header-cell *matHeaderCellDef>id</th>
<td mat-cell *matCellDef="let element">{{ element.post.id }}</td>
</ng-container>
<ng-container matColumnDef="title">
<th mat-header-cell *matHeaderCellDef>title</th>
<td mat-cell *matCellDef="let element">{{ element.post.title }}</td>
</ng-container>
<ng-container matColumnDef="body">
<th mat-header-cell *matHeaderCellDef>body</th>
<td mat-cell *matCellDef="let element">{{ element.post.body }}</td>
</ng-container>
<ng-container matColumnDef="userId">
<th mat-header-cell *matHeaderCellDef>userId</th>
<td mat-cell *matCellDef="let element">{{ element.user.userId }}</td>
</ng-container>
<ng-container matColumnDef="username">
<th mat-header-cell *matHeaderCellDef>username</th>
<td mat-cell *matCellDef="let element">{{ element.user.username }}</td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns"></tr>
</table>
Demo: https://stackblitz.com/edit/angular-tm2met?file=src%2Fusers%2Fusers.component.ts
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论