Angular State Management With NGXS
NGXS is a state management pattern + library for Angular. It acts as a single source of truth for your application's state, providing simple rules for predictable state mutations.


Learn How to Master Digital Trust

The State of Consumer Digital ID 2024

Top CIAM Platform 2024
In this article, we will learn about state management in Angular with NGXS. Here we will understand the basic concept of NGXS and create a simple TO-DO App.
What is State
In the bigger apps, managing the data states is very complicated. In angular, each component has its own state, to share the data/state between the components we normally use @Input and @Output decorators, but when the application goes bigger, its challenging to maintain the data consistency. So to solve this problem, redux was introduced. It provides a central store that holds all states of your application. Each component can access the stored state without sending it from one component to another.

What is NGXS
NGXS is a state management pattern + library. It provides as a single source of truth for your application's state, providing simple rules for predictable state mutations.
NGXS is modeled after the CQRS pattern popularly implemented in libraries like Redux and NgRx but reduces boilerplate by using modern TypeScript features such as classes and decorators.
How NGXS works:
NGXS is very simple to use as compared to other state management patterns like redux and Akita. NGXS takes full advantage of angular and typescript over the redux pattern. There are majors 4 concepts to NGXS
1. Store:
It is a global state container and manages the states of the application.We can dispatch the actions to perform certain operations.
1this.store.dispatch(new TodoActions.AddTodo(form));2. Actions
An action is a type of command which should be called when something happens or you want to trigger at any event like adding a new todo, listing todos etc.
1export class AddTodo {
2 static readonly type = '[Todo] Add';
3 constructor(public payload: ITodo) { }
4}3. State
States are classes along with decorators to describe metadata and action mappings.
1import { Injectable } from '@angular/core';
2import { State } from '@ngxs/store';
3@State<ITodoStateModel[]>({
4name: 'todoList',
5defaults: {
6todoList: [],
7},
8})
9@Injectable()
10export class TodoState {}4. Select
Selects are functions that slice a specific portion of the state from the global state container i.e. to get the data from the specific global state whenever you want to use.
1@Select(TodoState) todoList$: Observable<ITodo>;Let's build a To-Do App:
1. Get started
Install the npm install @ngxs/store --save then import the below code in app.module.ts
1//File name app.module.ts
2import { NgxsModule } from '@ngxs/store';
3@NgModule({
4 imports: [
5 NgxsModule.forRoot([ToDoState], { // here login state
6 developmentMode: !environment.production
7 })
8 ]
9})
10export class AppModule {}2. Create your store
Here we have created a component that dispatches actions to create a to-do and for other operations. Apart from that, we are using a selector TodoState, from which we are listening for the updated to-do list.
Put this code in the app.component.ts
1// File name app.component.ts
2import { Component } from '@angular/core';
3import { Store, Select } from '@ngxs/store';
4import { TodoActions } from './state/todo-actions';
5import { FormGroup, FormControl, Validators } from '@angular/forms';
6import { TodoState, ITodo } from './state/todo-state';
7import { Observable } from 'rxjs';
8@Component({
9 selector: 'app-root',
10 templateUrl: './app.component.html',
11 styleUrls: ['./app.component.scss']
12})
13export class AppComponent {
14 title = 'ngxs-todo-app';
15@Select(TodoState) todoList$: Observable<ITodo>;
16addForm = new FormGroup({
17title: new FormControl('', [Validators.required])
18});
19constructor(private store: Store){}
20onSubmit(form: any){
21this.store.dispatch(new TodoActions.AddTodo(form));
22}
23markDone(id: string, is_done: boolean){
24this.store.dispatch(new TodoActions.markDone(id, is_done));
25}
26}3. Create your actions
Create a folder state and put the todo-actions.ts file and add below code
1// File name todo-actions.ts
2export class AddTodo {
3 static readonly type = '[Todo] Add';
4 constructor(public payload: any) { }
5}
6export class EditTodo {
7static readonly type = '[Todo] Edit';
8constructor(public payload: any) { }
9}
10export class FetchAllTodos {
11static readonly type = '[Todo] Fetch All';
12}
13export class DeleteTodo {
14static readonly type = '[Todo] Delete';
15constructor(public id: number) { }
16}4. Create your State:
Here we have created the state of the todo, it contains the global state of the todo list.
Create a folder state and put the todo-state.ts file and add below code
1// File name todo-state.ts
2import { Injectable } from '@angular/core';
3import { State, NgxsOnInit, Action, StateContext } from '@ngxs/store';
4import { TodoActions } from './todo-actions';
5import { patch, updateItem } from '@ngxs/store/operators';
6export interface ITodo {
7id: string;
8title: string;
9is_done: boolean;
10}
11export interface ITodoStateModel {
12todoList: ITodo[];
13}
14@State<ITodoStateModel>({
15name: 'todoList',
16defaults: {
17todoList: [],
18},
19})
20@Injectable()
21export class TodoState implements NgxsOnInit {
22ngxsOnInit(ctx) {
23ctx.dispatch(new TodoActions.FetchAllTodos());
24}
25@Action(TodoActions.markDone)
26markDone(
27ctx: StateContext<ITodoStateModel>,
28{ payload, is_done }: TodoActions.markDone
29) {
30ctx.setState(
31patch({
32todoList: updateItem(
33(item: ITodo) => item.id === payload,
34patch({ is_done: !is_done })
35)
36})
37);
38}
39@Action(TodoActions.AddTodo)
40add(
41 ctx: StateContext<ITodoStateModel>,
42 { payload }: TodoActions.AddTodo,
43) {
44 const state = ctx.getState();
45 ctx.setState({
46 ...state,
47 todoList: [
48 ...state.todoList,
49 {
50 ...payload,
51 id: Math.random().toString(36).substring(7),
52 is_done: false
53 }
54 ],
55 }
56 );
57}
58
59}5. Create your html view
Here we have created a form that we use to create todo and listed all todos.
put this code in your app.component.html
1<!-- File name app.component.html -->
2<form [formGroup]="addForm" (ngSubmit)="onSubmit(addForm.value)">
3 <input type="text" formControlName="title" class="form-control todo-list-input" placeholder="What do you need to do today?">
4 <button class="add btn btn-primary font-weight-bold todo-list-add-btn">Add</button>
5</form>
6<ul class="d-flex flex-column-reverse todo-list">
7 <li *ngFor="let todo of (todoList$ | async) ?. todoList" [ngClass]="{'completed': todo.is_done}">
8 <div class="form-check">
9 <label class="form-check-label">
10 <input (click)="markDone(todo.id, todo.is_done)" class="checkbox" type="checkbox" [checked]="todo.is_done">{{todo.title}} <i class="input-helper"></i></label>
11 </div>
12 </li>
13 </ul>After lots of code, it's time to see the results. So here is the UI you will get. To get the complete code please go to Github Repo.

Conclusion
We have gone through the basic concepts of NGXS and built a simple to-do app. There are a lot of advanced features and plugins by NGXS, but beyond the scope, we could not add, but hopefully, we will be exploring in future blogs.
