How to get data from 2 api and view data in angular material table?

620 Views Asked by At

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

There are 1 best solutions below

2
On BEST ANSWER

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