如何从2个API获取数据并在Angular Material表格中查看数据?

huangapple go评论61阅读模式
英文:

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:

  1. Fetch the data from both APIs using your service methods, getPosts() and getUsers().

  2. In your component, subscribe to both API calls and store their responses in variables.

  3. Use JavaScript array methods like map() or forEach() to iterate through the data from the "users" API and find the corresponding username for each item in the "posts" API based on the userId.

  4. 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

你可以创建一个新的接口,将PostsListUsersList两者结合在一起,如下所示:

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[] = [&#39;id&#39;, &#39;title&#39;, &#39;body&#39;, &#39;userId&#39;, &#39;username&#39;];
  // Datasource for table
  dataSource: MatTableDataSource&lt;TableView&gt; =
    new MatTableDataSource&lt;TableView&gt;();

  constructor(private myService: UsersService) {}

  ngOnInit(): void {
    // Promise for getting results of both API&#39;s
    let dataPromise: Array&lt;Promise&lt;any&gt;&gt; = [];
    // 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) =&gt; {
      // 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&lt;TableView&gt; = [];

      posts.list.forEach((x) =&gt; {
        tableData.push({
          post: x,
          user: users.list.filter((y) =&gt; y.userId.toString() === x.userId)[0], // get the user for this userId
        });
      });
      this.dataSource = new MatTableDataSource&lt;TableView&gt;(tableData);
    });
  }
}

Now change your HTML to use new interface.

&lt;table mat-table [dataSource]=&quot;dataSource&quot; class=&quot;mat-elevation-z8&quot;&gt;
  Position Column
  &lt;ng-container matColumnDef=&quot;id&quot;&gt;
    &lt;th mat-header-cell *matHeaderCellDef&gt;id&lt;/th&gt;
    &lt;td mat-cell *matCellDef=&quot;let element&quot;&gt;{{ element.post.id }}&lt;/td&gt;
  &lt;/ng-container&gt;

  &lt;ng-container matColumnDef=&quot;title&quot;&gt;
    &lt;th mat-header-cell *matHeaderCellDef&gt;title&lt;/th&gt;
    &lt;td mat-cell *matCellDef=&quot;let element&quot;&gt;{{ element.post.title }}&lt;/td&gt;
  &lt;/ng-container&gt;

  &lt;ng-container matColumnDef=&quot;body&quot;&gt;
    &lt;th mat-header-cell *matHeaderCellDef&gt;body&lt;/th&gt;
    &lt;td mat-cell *matCellDef=&quot;let element&quot;&gt;{{ element.post.body }}&lt;/td&gt;
  &lt;/ng-container&gt;

  &lt;ng-container matColumnDef=&quot;userId&quot;&gt;
    &lt;th mat-header-cell *matHeaderCellDef&gt;userId&lt;/th&gt;
    &lt;td mat-cell *matCellDef=&quot;let element&quot;&gt;{{ element.user.userId }}&lt;/td&gt;
  &lt;/ng-container&gt;

  &lt;ng-container matColumnDef=&quot;username&quot;&gt;
    &lt;th mat-header-cell *matHeaderCellDef&gt;username&lt;/th&gt;
    &lt;td mat-cell *matCellDef=&quot;let element&quot;&gt;{{ element.user.username }}&lt;/td&gt;
  &lt;/ng-container&gt;

  &lt;tr mat-header-row *matHeaderRowDef=&quot;displayedColumns&quot;&gt;&lt;/tr&gt;
  &lt;tr mat-row *matRowDef=&quot;let row; columns: displayedColumns&quot;&gt;&lt;/tr&gt;
&lt;/table&gt;

Demo: https://stackblitz.com/edit/angular-tm2met?file=src%2Fusers%2Fusers.component.ts

huangapple
  • 本文由 发表于 2023年5月28日 18:50:13
  • 转载请务必保留本文链接:https://go.coder-hub.com/76351100.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定