Master Angular NgRx by creating a To-Do Application

Follow on LinkedIn

In this article we are building a todo application using Angular NgRx, NgRx is used for state management in angular applications.

Let’s start by creating a new Angular project if you haven’t already

ng new ngrx-todo-app

Go inside the project directory

cd ngrx-todo-app

Install the required angular NgRx packages

ng add @ngrx/store
ng add @ngrx/effects

Define the structure of your application’s state and actions for Angular NgRx project

Create a folder named actions in the src/app directory. In this folder, create an actions.ts file

import { createAction, props } from '@ngrx/store';

export const addTodo = createAction('[Todo] Add Todo', props<{ text: string }>());
export const completeTodo = createAction('[Todo] Complete Todo', props<{ id: number }>());

Create a folder named reducers in the src/app directory. In this folder, create a todos.reducer.ts file

import { createReducer, on } from '@ngrx/store';
import { addTodo, completeTodo } from '../actions/actions';

export interface Todo {
  id: number;
  text: string;
  completed: boolean;
}

export interface TodoState {
  todos: Todo[];
}

export const initialState: TodoState = {
  todos: [],
};

export const todoReducer = createReducer(
  initialState,
  on(addTodo, (state, { text }) => ({ ...state, todos: [...state.todos, { id: state.todos.length + 1, text, completed: false }] })),
  on(completeTodo, (state, { id }) => ({ ...state, todos: state.todos.map(todo => (todo.id === id ? { ...todo, completed: true } : todo)) }))
);

Now, create a folder named effects in the src/app directory. In this folder, create a todos.effects.ts file

import { Injectable } from '@angular/core';
import { Actions, createEffect, ofType } from '@ngrx/effects';
import { addTodo, completeTodo } from '../actions/actions';
import { tap } from 'rxjs/operators';

@Injectable()
export class TodosEffects {
  constructor(private actions$: Actions) {}

  completeTodo$ = createEffect(
    () =>
      this.actions$.pipe(
        ofType(completeTodo),
        tap(action => {
          console.log(`Todo with ID ${action.id} completed.`);
        })
      ),
    { dispatch: false }
  );
}

In the src/app directory, create an index.ts file to export everything from the actions, reducers, and effects

export * from './actions/actions';
export * from './reducers/todos.reducer';
export * from './effects/todos.effects';

Now, its time to create a todo component for our Angular Ngrx Project.

ng generate component todo

In the src/app/todo directory, modify the todo.component.ts

import { Component } from '@angular/core';
import { Store } from '@ngrx/store';
import { addTodo } from '../actions/actions';

@Component({
  selector: 'app-todo',
  templateUrl: './todo.component.html',
  styleUrls: ['./todo.component.css'],
})
export class TodoComponent {
  newTodoText: string = '';

  constructor(private store: Store) {}

  addTodo() {
    if (this.newTodoText.trim() !== '') {
      this.store.dispatch(addTodo({ text: this.newTodoText }));
      this.newTodoText = '';
    }
  }
}

Modify the todo.component.html

<div>
  <input [(ngModel)]="newTodoText" placeholder="Add a new todo" />
  <button (click)="addTodo()">Add</button>
</div>

In the src/app/app.component.html, use the <app-todo></app-todo> tag to include the todo component

In the src/app/app.module.ts, configure the NgRx store and effects

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { StoreModule } from '@ngrx/store';
import { EffectsModule } from '@ngrx/effects';
import { FormsModule } from '@angular/forms';
import { AppComponent } from './app.component';
import { TodoComponent } from './todo/todo.component';
import { todoReducer } from './reducers/todos.reducer';
import { TodosEffects } from './effects/todos.effects';

@NgModule({
  declarations: [AppComponent, TodoComponent],
  imports: [
    BrowserModule,
    FormsModule,
    StoreModule.forRoot({ todos: todoReducer }),
    EffectsModule.forRoot([TodosEffects]),
  ],
  providers: [],
  bootstrap: [AppComponent],
})
export class AppModule {}

Run the app using the following command

ng serve

Our app should be accessible at http://localhost:4200.

This is a basic example of how you can create a todo app using Angular NgRx for state management.

If you have any doubts, please comment. Happy Coding 🙂

Related Posts

1 Comment

Leave a Reply

Your email address will not be published. Required fields are marked *

×