Photo Credit: Alona Kraft

Building an Angular 4 application with @ngrx

Coskun Deniz
OlricDigital
Published in
6 min readJun 5, 2017

--

In this tutorial we will build an app that enables users to search food and get the nutrition facts of the them. The app will also enable users to add and remove foods to/from their food list. We assume that you are familiar with Angular v4, RxJS and ngrx/store. (You should check our previous post if you are not familiar with ngrx/store.)

DEMO REPO

Food API

There are many available APIs providing nutrition facts of the foods, we choose to use Food Search and Food Report APIs from USDA Food Composition Databases.

Here is how we use Food APIs:

  1. Make an Http request to get the related foods from Food Search API.
  2. Make a second Http request to get the nutrition facts of the selected food item from Food Report API.

Data Models

Let’s create our data models first. We have two data models; food and search result.

Food Search API returns a response including “ndbno” and food name. We will display the food name on the search result list and we will need “ndbno” to fetch nutrition facts at the next step.

And food model should look like this;

App Architecture

Let’s start designing the app architecture.

  • First we need a “search component” that contains input field for searching: “search-input.component”.
  • Then user makes a search and API returns a response. We call this response as “search results”. We need a component to show search results: “search-results.component”.
  • User wants to look at the food item in detail to check the nutrients values: “food-result.component”.
  • User might want to add the food to the favorite food list. So we need “food-list.component”.
  • Finally, we need a component that shows the details of a food from the user’s list: “food-detail.component”.
Component Architecture

State Management

It is impossible to pass data between components with @Input and @Output decorators since we have router-outlet between them. Therefore we need to implement a service to pass the data between components. We choose to implement Redux-like state management to our app. We will use ngrx/store library for the state management. (Alternatively you can create your own state management service using RxJS.)

As the starting point, we should create Actions and Reducer. But before working on Actions and Reducer, we need to install @ngrx/store.

npm install @ngrx/core @ngrx/store --save

Actions

Here are the fundamental action types in our app. New actions can be added when the app gets new features.

Let’s create the actual actions by defining their payloads.

Then we need to export actions to use them inside the reducer functions.

Reducer

A Reducer simply takes the action as an input and returns the new state according the action type and payload. We have defined our actions, now we should create our state model before writing the reducer function. Here is our state.

We need an initial state as a starting point. At the beginning we don’t have any data.

After we defined and initialized our state, we can create our reducer function.

The tricky part in the reducer function is the spread operator (…). You should get familiar with spread operator to make use of the reducers.

The spread syntax allows an expression to be expanded in places where multiple arguments (for function calls) or multiple elements (for array literals) or multiple variables (for destructuring assignment) are expected. Link

Store

Store can be thought as a meeting point where actions and reducers come together with the state. We will use Store module of @ngrx/store now.

Add the following line to app.module.ts:

Previously we have imported the Actions into our Reducer. Let’s import our Reducer into the store.

We completed state management section succesfully. Now we can use “store.dispatch” to call an action and “store.select” to give access our components to the state.

Services

Let’s create our service to communicate with the outside world before creating components. We call this service as NutritionService. NutritionService will have two function;

  1. Search foods
  2. Fetch the selected food detail

We created searchFood & fetchFood functions below. The functions basically make Http request and return response as Observable.

(Warning: You need to get your own API key from here.)

We created the store and service until now. But there is something missing. How to call service function in case of an action? We need to call the functions within our service upon a specific action type. For example, we need to call searchFood() from NutritionService when a component dispatches ‘SEARCH FOOD’ action.

The missing part is “@ngrx/effect” library. @ngrx/effect enables listening the actions and calling services according the action type.

Let’s install @ngrx/effects:

npm install @ngrx/effects --save

We have one listener for each function in NutritionService; searchFood$, fetchFood$.

Let’s add the effects module into our app.

We have done the hard part, and the rest is relatively easy. All we need to is create our components and the routing module.

Components

In this part, We will skip the component templates and focus on the component classes. We will use Angular Material library to implement nice UI design quickly. So you can use this repo to directly start to work on the app.

App Component

App component contains toolbar, search-input component and router-outlet as previously explained.

We don’t need any functionality in our AppComponent class since each component will have direct access to the Store. One important thing is to change ChangeDetectionStrategy from Default to OnPush to increase the performance of the app. (detailed explanation for the ChangeDetectionStrategy)

Here is the template of the AppComponent.

Search-Input Component

We want to get the results from the server as soon as the user starts to type. To do that we will make use of RxJS library.

We created an input field and gave it an identifier, “#input”, to observe its keyup events.

Now all we need is to dispatch an action when user types a search term.

Let’s add Store to SearchInputComponent and dispatch the ‘SEARCH’ action.

It’s done with only four lines of codes. Search-input component is now able to dispatch ‘SEARCH’ action which is its sole responsibility.

Search-Results Component

Search-results component is responsible for displaying search results obtained from the API. We have used @ngrx/effects to fetch the results and we have used a reducer to store it as “results”. Therefore the only thing we need to add inside search-results component is creating two variables and binding them to the store.

We created “results” and “loading” Observables and we bind them to the store as follows.

Food-Result Component

Food-result component is responsible to show nutrition facts of the selected food among the search results. We will use route parameters to let know the component which food is selected. When a food is selected, app goes to new route, and url state will look like this:

localhost:4200/search-results/id

Then we should get the (food) id from the routing parameters inside the FoodResultComponent.

After getting the id from the route parameters we need to dispatch actions that FoodResultComponent is responsible for.

FoodResultComponent is responsible for two actions:

1-Fetching the food info

2-Adding the food to the list

Food-List Component

We need a FoodListComponent to list the foods that user added in. FoodListComponent will show the food list and it will be able to dispatch ‘REMOVE_FOOD’ action.

Food-Detail Component

FoodResultComponent and FoodDetailComponent do almost the same job. The difference is that FoodDetailComponent shows the food directly from the food list where FoodResultComponent gets the data from the server.

Routing

We created the store (reducer + actions), service and components. Simplest part is left; routing.

Let’s start to create routes. We have 4 different routes: search-result, food-result, food-list and food-detail.

then import RouterModule with routes;

Congratulations! We have succesfully complete the nutrition app.

In this tutorial we learn how to use @ngrx/store and @ngrx/effect to enable our application to have modern state management. Now you can use this guide to build diverse complex app by following the same steps.

--

--

Coskun Deniz
OlricDigital

Software Developer, Angular Enthusiast, Typescript Lover