Tutorial: Building enterprise applications with Angular 6, NgRx and RxJs - Lesson 3
NgRx Store: https://github.com/ngrx/store
Angular 6: https://github.com/angular/angular
Steem API Docs: https://developers.steem.io/
Github repository: https://github.com/mightypanda-x/ngrx-tut
I spend good part of a weekend figuring out how to make multiple asynchronous functions call and return one merged result from all those calls when they are complete. Something like this is easily achievable using forkJoin on http calls but async methods are an older generation tech which are still very much popular. Unfortunately RxJS doesn't provide us with any methods to support this out of the box.
What will you learn in this tutorial?
- Using getContent function to get information of a post.
- Promisifying an async method.
- Combining promisified methods so all method returns are executed together and merged, similar to forkJoin.
Requirements
Difficulty: Intermediate
Clone and run git project
Clone the git project so you can follow along with the steps and run the application
$ git clone git@github.com:mightypanda-x/ngrx-tut.git
$ cd ngrx-tut
$ npm install
Actions
profile.actions.ts
export class RetrievePostDetails implements Action {
readonly type = ProfileActionTypes.RetrievePostDetails;
constructor(public payload: PostMetaModel[]) {}
}
Actions are dispatched to trigger a change in state.
This action takes payload of type PostMetaModel array as input. We need author name and permlink to get post information.
export class RetrievePostDetailsSuccess implements Action {
readonly type = ProfileActionTypes.RetrievePostDetailsSuccess;
constructor(public payload: PostModel[]) {}
}
This action will get called when retrieving post information is successful. It takes payload of type PostModel array. This payload is then set in the state object.
export class RetrievePostDetailsFailure implements Action {
readonly type = ProfileActionTypes.RetrievePostDetailsFailure;
constructor(public payload: string) {}
}
This action will be called when retrieve of posts fail. It takes payload of type string which is then used log and show errors.
Effects
profile.effects.ts
@Effect()
getPostDetails = this.actions.pipe(
ofType(ProfileActionTypes.RetrievePostDetails),
switchMap((action: RetrievePostDetails) => this.profileService.retrivePostsInfo(action.payload, (err, postList: PostModel[]) => {
if (err) {
catchError(error => this.profileService.handlePostRetrieveError(error));
}
if (postList.length > 0) {
this.store.dispatch(new RetrievePostDetailsSuccess(postList));
}
}))
);
Effect intercepts the RetrievePostDetails action and triggers call to service. Service then calls either the error method or the success action.
Service
profile.service.ts
All the above code was mostly basic NgRx code. This is where the actual magic happens and the reason for the tutorial.
private getPostInformation(author, permlink): Promise<any> {
return new Promise((resolve, reject) => {
steem.api.getContent(author, permlink, (err, postInformation) => {
if (err) {
reject(new Error(err));
} else {
resolve(postInformation);
}
});
});
}
This method will promisify the getContent async method. We make a call using steem api getContent method and pass in a callback method. That callback method will either resolve or reject the response. Promise will then be returned by the method.
public retrivePostsInfo(bids: PostMetaModel[], cb): Array<any> {
const methodCalls = [];
_.map(bids, (bid) => {
methodCalls.push(this.getPostInformation(bid.author, bid.permlink));
});
Promise.all(
methodCalls
).then((results) => {
cb(null, results);
});
return [];
}
This method will call above method one at a time and then combine all the promises using Promise.all method. Once all the promises are resolved, then is executed for Promise.all which returns a combined result from all the calls made.
Profile Reducer
profile.reducers.ts
case ProfileActionTypes.RetrievePostDetailsSuccess: {
return action.payload;
}
Reducer will simply update the state object with new information.
User Profile Component
user-profile.component.ts
getPosts() {
const inputData = [];
inputData.push({
author: 'mightypanda',
permlink: 'esteem-1-6-0-cannot-exit-set-pin-screen-without-setting-any-pin'
}, {
author: 'mightypanda',
permlink: 'steem-curator-sorting-feature-and-utopian-posts'
}, {
author: 'mightypanda',
permlink: 'steemcurator-com-update-sorting-and-special-posts-overview'
});
this.store.dispatch(new ProfileActions.RetrievePostDetails(inputData));
}
..............
this.userPosts = _.get(user, 'posts');
User Profile Component is where will dispatch action and subscribe to change in store.
user-profile.component.html
<div class="col-md-9">
<div *ngFor="let post of userPosts" class="col-md-12 postInfo">
<h4>{{post.title}}</h4>
<span>Category: {{post.category}}</span><br>
<span>Total Votes: {{post.active_votes.length}}</span>
</div>
</div>
This code simply iterates over the data array and displays the results on the page.
Running the application
Go the terminal and type
$ ng serve
This will compile and run the application on http://localhost:4200. Click on Get Posts link and it will retrieve data for some posts.