Codementor Events

Create an Angular Mobile App using NgRx

Published Dec 27, 2019
Create an Angular Mobile App using NgRx

In this blog, we are going to learn how to create Angular app with the help of NGRX entity. Also we are going to learn how NgRx Entity build a basic CRUD (select, create, update and delete) to build Angular mobile app. [Click to Tweet]

NgRx Entity manages collections of entities. It provides APIs to manipulate and query entity collections. NgRx Entity helps to reduce the boilerplate coding of reducers that manage collections of entities. NgRx Entity provides performant CRUD operations for managing entity collections.

Here in this blog, you will get the complete information with an example to add, update, remove and select the entities from the collections to build the Angular ToDo app using the NgRx entity.

Step 1. Set up the Development Environment.

You need to set up your development environment before you can do anything.

Install Node.js® and npm if they are not already on your machine.

Verify that you are running at least node 9.11.x and npm 6.x.x by running node -v and npm -v in a terminal/console window.

To install Angular CLI, run:

$ npm install -g angular-cli

This will install the ng command globally on your system.

To verify whether your installation completed successfully, you can run:

$ ng version

Step 2. Create a new App with Routing.

Now that you have Angular CLI installed, you can use it to generate your Todo application:

$ ng new todo-ngrx-entity --routing

This creates an app called todo-app and the –routing flag generates a file called app-routing.module.ts, which is one of the files you need for setting up lazy loading for your feature module.

Step 3. Install NgRx.

We will install the Entity, Store, and Effects using NPM as following:

$ npm install @ngrx/entity --save
$ npm install @ngrx/store --save
$ npm install @ngrx/effects --save

Step 4. Serve the application.

You can now navigate to the new directory:

$ cd todo-ngrx-entity

Then start the Angular CLI development server:

$ ng serve

This will start a local development server that you can navigate to in your browser at http://localhost:4200/

Step 5. Create a feature module with routing.

Using the Angular CLI, generate a new feature module named list.

$ ng generate module components/list --routing

This creates a list folder with two files inside; ListModule and ListRoutingModule.

Step 6. Add a component to the feature module.

Using the Angular CLI, generate a new component named list.

$ ng generate component components/list

This creates a folder inside of list called list with the four files that make up the component.

Step 7. Set up the UI.

Replace the default placeholder markup in app.component.html with a so you can easily navigate to your modules in the browser:

<router-outlet></router-outlet>

Angular ToDo App Development

Configure the routes.

The structure is as follows:
lazy-load-relationship-768x646.jpg
In the AppRoutingModule, you configure the routes to the feature modules, in this case, ListModule. This way, the router knows to go to the feature module.

The feature module then connects the AppRoutingModule to the ListRoutingModule. Those routing modules tell the router where to go to load relevant components.

Let’s start Lazy Loading

ROUTES AT THE APP LEVEL

Using the app router, point the lazy route to the lazy module. We can do this using loadChildren property with the path to the module file, then reference the module itself with a hash #. This tells angular to only load ListModule when the listing URL is activated.

src/app/app-routing.ts

import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router'; const routes: Routes = [ { path: '', redirectTo: 'add', pathMatch: 'full' }, { path: 'list', loadChildren: './components/list/list.module#ListModule' }, { path: 'add', loadChildren: './components/add/add.module#AddModule' }, { path: 'edit/:id', loadChildren: './components/edit/edit.module#EditModule' }
]; @NgModule({ imports: [RouterModule.forRoot(routes)], exports: [RouterModule], providers: []
})
export class AppRoutingModule {
}

INSIDE THE FEATURE MODULE

src/app/components/list/list.module.ts

import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { ListRoutingModule } from './list-routing.module';
import { ListComponent } from './list.component'; @NgModule({ imports: [CommonModule, ListRoutingModule], declarations: [ListComponent], providers: []
})
export class ListModule {
}

CONFIGURE THE FEATURE MODULE’S ROUTES

src/app/components/list/list-routing.module.ts

import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { ListComponent } from './list.component'; const routes: Routes = [ { path: '', component: 'ListComponent' }
]; @NgModule({ imports: [RouterModule.forRoot(routes)], exports: [RouterModule] })
export class ListRoutingModule {
}

INSIDE THE COMPONENT

src/app/components/list/list.component.ts

import {Component, OnInit} from '@angular/core';
import {Router} from '@angular/router';
import {Observable} from 'rxjs/Rx';
import {todo} from './../../models/todo.model';
import {TodoService} from './../../services/todo.service'; @Component({ selector: 'app-list', templateUrl: './list.component.html', styleUrls: ['./list.component.scss']
})
export class ListComponent implements OnInit { public todoSub: Observable<todo>; constructor(private router: Router , private todoService: TodoService ) { } ngOnInit() { this.todoSub = this.todoService.list(); } editRecord(id) { this.router.navigate(['/edit', id]); } deleteRecord(id) { this.todoService.remove(id); } public trackByToodFun(index, item) { return item.id; }
}

INSIDE THE ACTIONS

Action file that contains an enum of action types, action class and an exported type union of action classes. The action class has a ‘type’ property. They have an optional ‘payload’ property for sending in data to the reducer.

Actions are basically the same with NgRx Entity, but you will need to be careful to make sure the payload data is appropriate for the adapter method.

src/app/actions/todo.actions.ts

import {Injectable} from '@angular/core';
import {Action} from '@ngrx/store';
import {todo} from './../models/todo.model'; export const ADD_TODO = '[TODO] Add';
export const REMOVE_TODO = '[TODO] Remove';
export const UPDATE_TODO = '[TODO] Update'; export class AddTodo implements Action { readonly type = ADD_TODO; constructor(public payload: todo) { }
} export class UpdateTodo implements Action { readonly type = UPDATE_TODO; constructor(public id: number, public changes) { }
} export class RemoveTodo implements Action { readonly type = REMOVE_TODO; constructor(public id: number) { }
} export type Actions = AddTodo | UpdateTodo | RemoveTodo;

INSIDE THE REDUCERS

Reducer contains a state interface, an initial state object for the reducer, and a reducer function. Reducers are pure functions that are the only ones that can change state. They aren’t really changing state but making a copy of existing state and changing one or more properties on the new state.

NgRx Entity provides EntityState interface that is a predefined generic interface for a given entity collection.

NgRx Entity has EntityAdapter interface that provides many collection methods for managing the entity state.

createEntityAdapter method instantiates generic EntityAdapter for a single entity state collection.

EntityAdapter has getInitialState method to get initial state of the entity, getSelectors method to get entity selectors. EntityAdapter extends EntityStateAdapter and inherits its methods to add, update and remove entities.

The entity adapter will allow us to take a collection and manage it with a set of Adapter Collection Methods are addOne, updateOne and removeOne, etc.

src/app/reducers/todo.reducer.ts

import {Action} from '@ngrx/store';
import {todo} from './../models/todo.model';
import *as TodoActions from './../actions/todo.actions';
import {EntityState, EntityAdapter, createEntityAdapter} from '@ngrx/entity';
import {createSelector, createFeatureSelector} from '@ngrx/store'; export interface TodoState extends EntityState<todo> { } export const adapter : EntityAdapter<todo> = createEntityAdapter<todo>({ }); const initialState : todo = <todo>{ }; export const initialTodoState : TodoState = adapter.getInitialState( ); export function todoReducers(state = initialTodoState, action: TodoActions.Actions) { switch(action.type) { case TodoActions.ADD_TODO: return adapter.addOne(action.payload, state); case TodoActions.UPDATE_TODO: if(state.entities[action.id] === undefined) { return state; } return adapter.updateOne({ id: action.id, changes: action.changes, }, state); case TodoActions.REMOVE_TODO: return adapter.removeOne(action.id, state); default: return state; }
} export const getTodoState = createFeatureSelector<TodoState>('todos'); export const {selectAll, selectEntities, selectIds, selectTotal} = adapter.getSelectors(getTodoState);

INSIDE THE SERVICES

The operation triggered by dispatching an action is going to be a pure function called, within the redux architecture, reducers. These reducers receive action and the state, depending on the action dispatched, they perform an operation and return a new state object.

When using the createSelector and createFeatureSelector functions @ngrx/store keeps track of the latest arguments in which your selector function was invoked. Due to selectors are pure functions, the last result can be returned when the arguments match without re-invoking your selector function. This can provide performance benefits.

The createSelector can be used to select some data from the state based on several slices of the same state.

NgRx. selectors also accept an extra props argument. Which means you can now define a selector like the following example:

src/app/services/todo.service.ts

import {Injectable} from '@angular/core';
import {Observable} from 'rxjs/Rx';
import *as TodoActions from './../actions/todo.actions';
import *as fromTodoReducer from './../reducers/todo.reducer';
import {createSelector, createFeatureSelector} from '@ngrx/store';
import {Dictionary} from '@ngrx/entity';
import {Store, select} from '@ngrx/store';
import {AppState} from './../app.state';
import {todo} from './../models/todo.model'; @Injectable()
export class TodoService { private allTodos; private todoById; constructor(private store: Store<AppState>) { this.allTodos = createSelector(fromTodoReducer.selectAll, (entities) => { return entities; }); this.todoById = createSelector(fromTodoReducer.selectEntities, (entities: Dictionary<todo>, props:{id: number}) => { return entities[props.id]; }); } public add(data: todo) { data.id = new Date().getTime(); this.store.dispatch(new TodoActions.AddTodo(data)); } public list(){ return this.store.pipe(select(this.allTodos)); } public remove(id: number) { this.store.dispatch(new TodoActions.RemoveTodo(id)); } public getDetail(id: number) { return this.store.pipe(select(this.todoById, {id: id})); } public edit(id: number, changes: todo) { this.store.dispatch(new TodoActions.UpdateTodo(id, changes)); } }

You can download the source code for this Angular mobile App from github repository angular-todo-app-ngrx-entity. So these are all steps you can follow to build Angular mobile app using NgRx entity. Surely it helps you!!

Discover and read more posts from Sanjay Patoliya
get started
post commentsBe the first to share your opinion
Show more replies