Tutorial: Building enterprise applications with Angular 6, NgRx and RxJs - Lesson 3

Words
449
Reading
2 min
Listen
Play
8y

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

  • Complete first and second tutorial
  • Basic knowledge of JS, Angular and RxJs

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.

ezgif.com-video-to-gif.gif

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.

GitHub for the tutorial:

https://github.com/mightypanda-x/ngrx-tut