Published in · 8 min read · 5 days ago
--
In this article I will show a full guide on how to make use of ngrx store with Angular to perform basic CRUD operations.
NgRx is a framework for building reactive applications in Angular. NgRx provides libraries for:
Managing global and local state.
Isolation of side effects to promote a cleaner component architecture.
Entity collection management.
Integration with the Angular Router.
Developer tooling that enhances developer experience when building many different types of applications.
Create, Read, Update, and Delete (CRUD) are the four basic functions that models should be able to do, at most.
I will create an angular project from scratch to showcase the usage of NGRX in order to handle simple CRUD operations. Also we will install all required packages from ngrx after creating the Angular application. Follow the steps as described below:
- Install angular cli as global package from npm → Open a terminal and run the following command:
npm i -g @angular/cli
2. Now let’s create a new angular project → Run the follwing command and you will be prompted to add Routing (I chose to accept, it will configure initial routes for you) and choose your preferred stylesheet format (I like SASS that’s why I chose to use SCSS).
ng new crud-ngrx-angular
3. Open the project in your preferred IDE and let’s get into bussiness.
We are going to need some packages provided by ngrx in order to make a full use of it’s store management power. Let’s do it. Open a new terminal and run the following.
- ngrx store → This package will provide us the basic StoreModule where we can initialize reducers (primitive functions which update the store object). You can learn more about reducers here.
npm i @ngrx/store
2. ngrx effects → This package provides side effetcs model for the Store. In short terms effects listen to a dispatched action and perform a side effect of the action, which can be stuff like calling an api service, updating local storage and of course dispacthing other actions. You can check out Effects docs here.
npm i @ngrx/effects
3. ngrx router store → Bindings to connect the Angular Router with Store. Check it’s documentation here.
npm i @ngrx/router-store
4. Optional: ngrx store dev tools → This package includes developer tools for ngrx. There is also a good chrome extension called Redux Dev Tools. You can add it to your Chrome and there you can see pretty much the store object, what actions we’re dispatching with their respective parameters and everything you need for debugging. It’s recommended to use this only in dev environment and to disable when you’re doing production build.
npm i @ngrx/store-devtools
As a showcase for this example I will use an online booking store with CRUD operations. So I will create a page where you can fetch a list of books, create a new book, update an existing book name and of course deleting. Let’s do it.
- Create a folder under app and call it store and inside of it create another folder called book.
- Create another folder which will hold the interfaces we need (We love typescript) and call it interfaces.
- In the interfaces folder go ahead an create a typescript file called book.interface.ts which looks like the follwing:
export interface IBook {
id: number;
name: string;
}
4. Create a folder called services. This will be responsible for having the book.service.ts file which in purpose has the api communication with an API. In my example I will mock everything in the service and return an observable from there but feel free to replace the functions with an http call. There will be 4 functions in the service to fetch, create, update and delete books. The file will look like below:
import { Injectable } from '@angular/core';
import { IBook } from '../interfaces/book.interface';
import { Observable, of } from 'rxjs';@Injectable({
providedIn: 'root'
})
export class BookService {
private booksList: IBook[] = [
{
id: Math.random(),
name: 'Book 1'
},
{
id: Math.random(),
name: 'Book 2'
}
]
constructor() {
}
getBooks(): Observable<IBook[]> {
return of(this.booksList);
}
create(book: IBook): Observable<IBook> {
this.booksList = [
...this.booksList,
book
];
return of(book);
}
update(updateBook: IBook): Observable<IBook> {
this.booksList.map(book => book.id === updateBook.id ? updateBook : book);
return of(updateBook);
}
delete(book: IBook): Observable<IBook> {
this.booksList = this.booksList.filter(b => b.id !== book.id);
return of(book);
}
}
5. book.model.ts → Create this file under store/book folder. This will hold the interface of books store.
import { IBook } from '../../interfaces/book.interface';export interface IBookState {
books: IBook[];
isLoading: boolean;
}
6. Under store/book create a file called books.actions.ts → This file will hold all the actions we need to implement the basic CRUD operations.
import { createAction, props } from '@ngrx/store';
import { IBook } from '../../interfaces/book.interface';const prefix = '[Books]';
export const getBooks = createAction(`${prefix} Get Books`);
export const getBooksSuccess = createAction(
`${getBooks.type} Success`,
props<{
books: IBook[];
}>()
);
export const createBook = createAction(
`${prefix} Create Book`,
props<{
book: Partial<IBook>;
}>()
);
export const createBookSuccess = createAction(
`${createBook.type} Success`,
props<{
book: IBook;
}>()
);
export const updateBook = createAction(
`${prefix} Update Book`,
props<{
book: IBook;
}>()
);
export const updateBookSuccess = createAction(
`${updateBook.type} Success`,
props<{
book: IBook;
}>()
);
export const deleteBook = createAction(
`${prefix} Delete Book`,
props<{
book: IBook;
}>()
);
export const deleteBookSuccess = createAction(
`${deleteBook.type} Success`,
props<{
book: IBook;
}>()
);
7. index.ts → export everything from actions and selectors. It will help a lot in the imports
export * from './book.actions';
export * from './books.selectors';
8. book.effects.ts → Here we will manage all side effects from action dispatching. In our case we will be calling the books service to manipulate the data.
import { Injectable } from '@angular/core';import { Actions, createEffect, ofType } from '@ngrx/effects';
import { map, switchMap } from 'rxjs/operators';
import * as fromBooks from './index';
import { BookService } from '../../services/book.service';
import { IBook } from '../../interfaces/book.interface';
@Injectable()
export class BooksEffects {
constructor(private readonly actions$: Actions, private readonly bookService: BookService) {
}
getBooks$ = createEffect(() =>
this.actions$.pipe(
ofType(fromBooks.getBooks.type),
switchMap(() => this.bookService.getBooks()),
map((books: IBook[]) => fromBooks.getBooksSuccess({books}))
)
);
createBook$ = createEffect(() =>
this.actions$.pipe(
ofType(fromBooks.createBook),
switchMap(({book}) => this.bookService.create(book)),
map((book: IBook) => fromBooks.createBookSuccess({book}))
)
);
updateBook$ = createEffect(() =>
this.actions$.pipe(
ofType(fromBooks.updateBook),
switchMap(({book}) => this.bookService.update(book)),
map((book: IBook) => fromBooks.updateBookSuccess({book}))
)
);
deleteBook$ = createEffect(() =>
this.actions$.pipe(
ofType(fromBooks.deleteBook),
switchMap(({book}) => this.bookService.delete(book)),
map((book: IBook) => fromBooks.deleteBookSuccess({book}))
)
);
}
9. book.reducers.ts → Reducers are responsible for updating the state. We do it by using pure functions like destructuring.
import { createReducer, on } from '@ngrx/store';import { IBookState } from './book.model';
import * as fromBooks from './index';
export const initialBooksState: IBookState = {
books: [],
isLoading: false
};
const reducer = createReducer<IBookState>(
initialBooksState,
on(fromBooks.getBooks, (state) => {
return {
...state,
isLoading: true
};
}),
on(fromBooks.getBooksSuccess, (state, { books }) => {
return {
...state,
isLoading: false,
books
};
}),
on(fromBooks.createBook, (state) => {
return {
...state,
isLoading: true,
};
}),
on(fromBooks.createBookSuccess, (state, { book }) => {
return {
...state,
books: [...state.books, book],
isLoading: false,
};
}),
on(fromBooks.updateBook, (state) => {
return {
...state,
isLoading: true,
};
}),
on(fromBooks.updateBookSuccess, (state, { book }) => {
return {
...state,
books: state.books.map((b) => b.id === book.id ? book : b),
isLoading: false,
};
}),
on(fromBooks.deleteBook, (state) => {
return {
...state,
isLoading: true,
};
}),
on(fromBooks.deleteBookSuccess, (state, { book }) => {
return {
...state,
isLoading: false,
books: state.books.filter((b) => b.id !== book.id)
};
})
);
export function booksReducer(state = initialBooksState, actions): IBookState {
return reducer(state, actions);
}
10. book.selectors.ts → Selectors fetch data from the store and return it as an observable.
import { createFeatureSelector, createSelector } from '@ngrx/store';import { IBookState } from './book.model';
export const selectBookState = createFeatureSelector<IBookState>('book');
export const selectBooksList = createSelector(selectBookState, (state) => state.books);
export const selectBookIsLoading = createSelector(selectBookState, (state) => state.isLoading);
(Video) Angular(v14) CRUD Example Using NgRx Data(v14)
11. book-store.module.ts → Here we will register book feature store with respective reducers and effects.
import { NgModule } from '@angular/core';import { EffectsModule } from '@ngrx/effects';
import { StoreModule } from '@ngrx/store';
import { BookEffects } from './book.effects';
import { bookReducer } from './book.reducers';
@NgModule({
imports: [
StoreModule.forFeature('book', bookReducer),
EffectsModule.forFeature([BookEffects])
]
})
export class BookStoreModule {}
12. Now we have all ngrx feature store for books in place. Let’s import the feature store module into app.module.ts and make use of StoreDevToolsModule to log our state on Redux dev tools on Chrome.
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { StoreModule } from '@ngrx/store';
import { EffectsModule } from '@ngrx/effects';
import { BookStoreModule } from './store/book/book-store.module';
import { StoreDevtoolsModule } from '@ngrx/store-devtools';
@NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule,
AppRoutingModule,
StoreModule.forRoot(),
EffectsModule.forRoot(),
StoreDevtoolsModule.instrument({}),
BookStoreModule,
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule {
}
13. If everything was implemented successfully you can run the following command to serve the angular app:
ng serve
and open Chrome dev tools → navigate to Redux like below and click it.
You should have the overview of your NGRX store. Yayy 🚀🚀 !!
13. Let’s see how it works in a component. I will use an HTML simple table and buttons to showcase the functionality, but of course you can perfect your stylesheet and the look of it.
- Delete everything in the app.component.html file.
- app.component.ts file will hold the logic for CRUD operations like getting the books, creating, updating and deleting. You can see the code below:
import { Component, OnInit } from '@angular/core';
import { Observable } from 'rxjs';
import { IBook } from './interfaces/book.interface';
import { select, Store } from '@ngrx/store';
import * as fromBooks from './store/book/index';@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss']
})
export class AppComponent implements OnInit {
books$: Observable<IBook[]>;
isLoading$: Observable<boolean>;
constructor(private readonly store: Store) {
}
ngOnInit(): void {
this.initDispatch();
this.initSubscriptions();
}
onCreateBook(name: string): void {
this.store.dispatch(fromBooks.createBook({
book: {
id: Math.random(),
name
}
}));
}
onUpdateBook(book: IBook): void {
this.store.dispatch(fromBooks.updateBook({book}));
}
onDeleteBook(book: IBook): void {
this.store.dispatch(fromBooks.deleteBook({book}));
}
private initDispatch(): void {
this.store.dispatch(fromBooks.getBooks());
}
private initSubscriptions(): void {
this.books$ = this.store.pipe(select(fromBooks.selectBooksList));
this.isLoading$ = this.store.pipe(select(fromBooks.selectBookIsLoading));
}
}
- app.component.html → Basic HTML buttons and table to show the example
<ng-container
*ngIf="{
books: books$ | async,
isLoading: isLoading$ | async
} as data"
>
<div class="header">
<input #inputElement>
<button (click)="onCreateBook(inputElement.value)">Create book</button>
</div>
<div class="container">
<table>
<th>ID</th>
<th>Name</th>
<th>Action</th>
<tbody>
<tr *ngFor="let book of data.books">
<td>{{book.id}}</td>
<td>{{book.name}}</td>
<td><button (click)="onDeleteBook(book)">Delete</button></td>
</tr>
</tbody>
</table>
</div>
</ng-container>
As usual, thank you for reading. I appreciate the time you take to read my content and stories. I hope you can find this article useful.
PS: I have pushed all the code used for this article in my bitbucket respository here. If you want to go deeper and add unit tests with JEST to your freshly created NGRX store you can visit my article here.
Stay tuned and happy coding!
FAQs
What are crud operations in Angular? ›
CRUD stands for the four functions create, read, update, and delete in computer programming. They are used to implement persistent storage applications and relational database applications: Create: A create operation allows you to add a new record to a table.
Should I use NgRx or not in Angular? ›NgRx is a popular solution in the Angular ecosystem if you are building complex web applications with sophisticated state management. Characteristics of the need for NgRx are many user interactions and multiple data sources. NgRx is a good choice, if: the state should be accessed by many components and services.
What is difference between NgRx and RxJS? ›RxJS is for handling complex asynchronous work like handling communication between client and server. Ngrx is for optimally storing data in the client and recalling them from all over the application, usually. If you want to take advantage of single direction data flow using Store in Angular NgRx is the solution.
How to implement NgRx in Angular? ›- Create an Angular App With Angular CLI. Let's create a new Angular Application. ...
- Load the Project Into the IDE (I'm Using IntelliJ IDEA)
- Run the App. ...
- Install NgRx and Tools. ...
- Add an NgRx Store to the App. ...
- Create a sub Module for Customer. ...
- Create a Customer model. ...
- Add Actions.
Create a folder called Angular CRUD in your system. And inside that folder, create two files. One is the client, and the other is the server. The client will contain our Angular Application, and the server will have the backend code for the server, built using Node, Express, and MongoDB.
What are the 4 CRUD operations? ›CRUD (Create, Read, Update, and Delete) is a basic requirement when working with database data.
What should I learn first NgRx or RxJS? ›RxJS or NgRX? You should learn RxJS at the same time as you learn Angular. Only then should you look into NgXS / NgRX, and only if necessary. An Engineer using Angular that doesn't know and utilize RxJS, is a liability to their company.
Why we need NgRx in Angular? ›NgRx is a framework for building reactive applications in Angular. NgRx is inspired by the Redux pattern - unifying the events in your application and deriving state using RxJS. At a high level, NgRx stores a single state and uses actions to express state changes.
What is NgRx in simple words? ›Ngrx is a group of Angular libraries for reactive extensions. Ngrx/Store implements the Redux pattern using the well-known RxJS observables of Angular 2. It provides several advantages by simplifying your application state to plain objects, enforcing unidirectional data flow, and more.
How to call API using NgRx in Angular? ›You need to run this command npm install @ngrx/effects — save to install required dependencies. You have to define the actual services to make the API calls. Finally, you need to register all the effects with the EffectsModules and import this module into your main module or feature module.
How to learn NgRx? ›
- Write down all the modules based on the features we need to achieve.
- Consider each function as a component in the module.
- Write down all the actions, selectors, and reducers we need to create to manage our state.
It's mainly because of Angular's unpopularity due to Angular 1.0, where developers had dismissed the framework as too complicated since it required a lot of time for learning. Although, Angular is developed by Google which provides constant improvements and long-term support for the framework.
Is Angular outdated? ›In January of 2018 we laid out our plans for the final releases of AngularJS before entering long-term support and last year, we extended the LTS due to the global pandemic until December 31, 2021. Well, friends, the time has come and we're no longer supporting AngularJS.
Why do people still use Angular? ›One of the main benefits of using Angular is that it provides a structure for building web applications. It uses a component-based architecture, which allows for the creation of reusable and modular components that can be easily maintained and scaled.
What is CRUD operations for beginners? ›CRUD refers to the four basic operations a software application should be able to perform – Create, Read, Update, and Delete. In such apps, users must be able to create data, have access to the data in the UI by reading the data, update or edit the data, and delete the data.
How to create REST API for CRUD operations? ›- Create Web API Project. In the New Project popup, select Web template under Visual C#. ...
- Select Web API Project Template. ...
- Change Authentication. ...
- Web API Project. ...
- Create Entity Data Model. ...
- Generated Entities in the EDM Designer. ...
- .edmx in the Project. ...
- Create Web API Controller.
CRUD is 4 distinct operations and there are seven RESTful actions. Create, Read, Update, Edit, Delete are CRUD actions. R of CRUD holds Index, New, Show, Edit and Edit, and Delete. The actions determine whether your consuming data, or feeding it, all the others are feeding it.
What are the 7 CRUD actions? ›The seven actions that perform our CRUD operations are index, new, create, show, edit, update, and destroy.
What is the difference between REST API and CRUD operations? ›REpresentational State Transfer—or REST—is an architectural style for creating APIs that communicate over the HTTP protocol. Behind the scenes, APIs often need to manipulate data as part of their operation. Typically, these data operations—called CRUD for short—run against backend databases.
Should I learn Angular as a beginner? ›Developers who are familiar with Angular will immediately recognize many of the practices within your project. This familiarity immensely boosts productivity. Being able to jump into a project with little help is highly valuable, both for the existing team on the project and the newbies!
How to learn Angular from beginner to advanced? ›
- Angular CLI Deep Dive: Setting up your first Angular project with the Angular CLI.
- NgModules: Learn about feature modules and core modules.
- Core Components: Understand the building blocks of Angular.
- Structural Directives: Make conditional changes to the DOM.
AngularJS extends HTML with new attributes. AngularJS is perfect for Single Page Applications (SPAs). AngularJS is easy to learn.
What is NgRx in Angular interview questions? ›[NG] What is ngRx ? Describe the Redux pattern. Like Redux for React, Vuex for Vue, ngRx is the Angular library allowing to integrate a Store into your application. It's a way to centralize data and manage the way it comes through the app.
How to store data in NgRx store? ›- Step 1: capture user interaction. ...
- Step 2: emit event to container. ...
- Step 3: Dispatch action to reducer. ...
- Step 4: Process action in reducer. ...
- Step 5: Display state in UI. ...
- Step 1: capture user interaction. ...
- Step 2: emit event to container. ...
- Step 3: Dispatch action to reducer.
Where Does NgRx Store Data? NgRx stores the application state in an RxJS observable inside an Angular service called Store. At the same time, this service implements the Observable interface. So, when you subscribe to the store, the service actually forwards the subscription to the underlying observable.
What is the best state management for Angular? ›When it comes to Angular, NgRx and NGXS are the two most-used libraries for state management, and they have some unique features that make developers' work easy. In this article, I will introduce NgRx and walk you through the steps of creating a simple Angular application using it.
Is NgRx a framework? ›NgRx is a framework for building reactive applications in Angular. NgRx provides state management, isolation of side effects, entity collection management, router bindings, code generation, and developer tools that enhance developers experience when building many different types of applications.
What is Angular in simple word? ›Angular is a platform and framework for building single-page client applications using HTML and TypeScript. Angular is written in TypeScript. It implements core and optional functionality as a set of TypeScript libraries that you import into your applications.
How API is called in Angular? ›We usually make API calls to remote HTTP servers via HttpClient module of Angular 10 by sending HTTP requests. HttpClient has methods which perform HTTP requests. HttpClient is an injectable class for Angular 10.
How to make two API calls in Angular? ›Call The API with RXJS ForkJoin
The ForkJoin Operator from RXJS is best when we need to call multiple API calls and combine them and do some calculations or processing before returning the result.
How to call API directly in Angular? ›
- Angular.
- → STEP 1: Find an API.
- → STEP 2: Create the application.
- → STEP 3: Start the application.
- → STEP 4: Formulate the API Request.
- → FINAL STEP: The API response.
- Wrap Up.
- Open the Command Prompt and create a folder.
- Now run the command - ng new AngularDemo.
- Now, Put “N” for Would you like to Add Angular Routing options (Since it needs to be Y when we want to use Routing in our applications).
- Choose stylesheet style as CSS and then press enter.
- import { Action } from '@ngrx/store';
- export enum ActionTypes {
- Login = '[Login Page] Login',
- }
- export class Login implements Action {
- readonly type = ActionTypes. Login;
- constructor(public payload: { username: string; password: string }) {}
- }
- import { createSelector } from '@ngrx/store';
- export interface FeatureState {
- counter: number;
- }
- export interface AppState {
- feature: FeatureState;
- }
- export const selectFeature = (state: AppState) => state. feature;
- The Series “Angular: From Theory to Practice” With Asim Hussain. ...
- Angular Full Course in 6 Hours With Edureka. ...
- Angular—The Complete Guide (2022 Edition) by Udemy. ...
- Angular Fundamentals Course on Ultimate Courses. ...
- FreeCodeCamp.
If you are ready to spend at least 2-3 hours daily on learning Angular then around 2-3 months are sufficient.
Can we learn Angular 8 directly? ›Angular community has released its latest version which is known as Angular 8. If you are familiar with previous version of Angular, it will not be difficult for you. You can easily upgrade your Angular CLI to version 8.
What does CRUD operations do? ›CRUD is the acronym for CREATE, READ, UPDATE and DELETE. These terms describe the four essential operations for creating and managing persistent data elements, mainly in relational and NoSQL databases.
What does CRUD operation mean? ›CRUD is an acronym that comes from the world of computer programming and refers to the four functions that are considered necessary to implement a persistent storage application: create, read, update and delete.
What are the CRUD operations in REST API? ›CRUD stands for Create, Read, Update, and Delete, which make up these four fundamental operations. Because REST API calls invoke CRUD operations, understanding their relationship with one another is important for API developers and data engineers.
What is CRUD vs REST operations? ›
REST is an architectural system centered around resources and Hypermedia using HTTP commands. CRUD is a cycle meant to maintain records in a database setting. In its base form, CRUD is a way of manipulating information, describing the function of an application. REST is controlling data through HTTP commands.
What are the 7 aspects of CRUD? ›CRUD is 4 distinct operations and there are seven RESTful actions. Create, Read, Update, Edit, Delete are CRUD actions. R of CRUD holds Index, New, Show, Edit and Edit, and Delete. The actions determine whether your consuming data, or feeding it, all the others are feeding it.
What are the steps of CRUD operation? ›Create, Read, Update and Delete are the four basic functions of persistent storage. These operations are usually referred to using the acronym CRUD.
How do I create a CRUD application? ›A CRUD app is a specific type of software application that consists of four basic operations; Create, Read, Update, Delete. At a high level, CRUD apps consist of three parts; the database, user interface, and APIs.
What is an example of a CRUD database? ›CRUD refers to the four operations we use to implement persistent storage applications like relational databases. Examples of relational databases include Oracle, Microsoft SQL Server, and MySQL.
How do you perform a CRUD test? ›- Identify what you are testing. The application we are going to test, is a typical CRUD style application that administrators of web applications are very used to. ...
- Make a plan. First up, you want to come up with a test plan so you can get good test coverage. ...
- Write some tests.
REST API uses web services and is based on request and response, whereas RESTful API works completely based on REST application and infrastructure. REST apps have strong protocols and pre-configured architecture layers as security measures, whereas RESTful apps have multi-layered transport protocols.
What is the difference between soap and REST and CRUD? ›REST allows clients to access “data” using resource URLs. SOAP, on the other hand, involves accessing API “functions” that manipulate data. Unlike REST, no methods (CRUD operations) are part of a request. Instead, separate functions handle CRUD operations on the same data object.
What is the difference between REST API and HTTP? ›REST APIs support more features than HTTP APIs, while HTTP APIs are designed with minimal features so that they can be offered at a lower price. Choose REST APIs if you need features such as API keys, per-client throttling, request validation, AWS WAF integration, or private API endpoints.
What is soap vs REST? ›REST is a set of guidelines that offers flexible implementation, whereas SOAP is a protocol with specific requirements like XML messaging. REST APIs are lightweight, making them ideal for newer contexts like the Internet of Things (IoT), mobile application development, and serverless computing.
What is REST API and example? ›
For example, a REST API would use a GET request to retrieve a record, a POST request to create one, a PUT request to update a record, and a DELETE request to delete one. All HTTP methods can be used in API calls. A well-designed REST API is similar to a website running in a web browser with built-in HTTP functionality.