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 :
{
"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
}
{
"list": [
{
"userId": 1,
"username": "Michil"
},
{
"userId": 2,
"username": "Alix"
},
{
"userId": 3,
"username": "Jon"
}
],
"count": 3,
"success": true
}
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
}
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)),
);
}
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);
})
);
}
<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 ?
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