NgRx Entity is a library that provides a set of helper functions to manage collections of entities in a store. It simplifies the process of managing collections by providing utilities for CRUD operations, sorting, and filtering. This module will cover the basics of NgRx Entity, how to set it up, and how to use it effectively in your Angular applications.

Key Concepts

  1. Entity: An object that represents a single item in a collection.
  2. Entity State: The state structure that holds the collection of entities.
  3. Entity Adapter: A set of functions that help manage the collection of entities.
  4. Selectors: Functions that help retrieve specific pieces of state.

Setting Up NgRx Entity

Step 1: Install NgRx Entity

First, you need to install the NgRx Entity package. Run the following command in your Angular project:

npm install @ngrx/entity

Step 2: Define Entity Model

Define the model for the entity you want to manage. For example, let's say we are managing a collection of Book entities:

export interface Book {
  id: string;
  title: string;
  author: string;
}

Step 3: Create Entity State

Define the state structure for the entity collection. Use the EntityState interface provided by NgRx Entity:

import { EntityState, EntityAdapter, createEntityAdapter } from '@ngrx/entity';

export interface BookState extends EntityState<Book> {
  // additional state properties if needed
  selectedBookId: string | null;
}

export const adapter: EntityAdapter<Book> = createEntityAdapter<Book>();

export const initialState: BookState = adapter.getInitialState({
  // additional state properties initialization
  selectedBookId: null,
});

Step 4: Create Reducer

Use the entity adapter to create a reducer that handles actions related to the entity collection:

import { createReducer, on } from '@ngrx/store';
import { Book } from './book.model';
import { adapter, BookState } from './book.state';
import * as BookActions from './book.actions';

export const bookReducer = createReducer(
  initialState,
  on(BookActions.addBook, (state, { book }) => {
    return adapter.addOne(book, state);
  }),
  on(BookActions.updateBook, (state, { update }) => {
    return adapter.updateOne(update, state);
  }),
  on(BookActions.deleteBook, (state, { id }) => {
    return adapter.removeOne(id, state);
  }),
  on(BookActions.loadBooks, (state, { books }) => {
    return adapter.setAll(books, state);
  })
);

Step 5: Create Selectors

Create selectors to retrieve specific pieces of state from the entity collection:

import { createFeatureSelector, createSelector } from '@ngrx/store';
import { adapter, BookState } from './book.state';

export const selectBookState = createFeatureSelector<BookState>('books');

const { selectIds, selectEntities, selectAll, selectTotal } = adapter.getSelectors();

export const selectBookIds = createSelector(selectBookState, selectIds);
export const selectBookEntities = createSelector(selectBookState, selectEntities);
export const selectAllBooks = createSelector(selectBookState, selectAll);
export const selectBookTotal = createSelector(selectBookState, selectTotal);

export const selectCurrentBookId = createSelector(
  selectBookState,
  (state: BookState) => state.selectedBookId
);

export const selectCurrentBook = createSelector(
  selectBookEntities,
  selectCurrentBookId,
  (bookEntities, bookId) => bookId ? bookEntities[bookId] : null
);

Practical Example

Let's create a simple example to demonstrate how to use NgRx Entity in an Angular application.

Step 1: Define Actions

Define actions for adding, updating, deleting, and loading books:

import { createAction, props } from '@ngrx/store';
import { Book } from './book.model';
import { Update } from '@ngrx/entity';

export const addBook = createAction(
  '[Book List] Add Book',
  props<{ book: Book }>()
);

export const updateBook = createAction(
  '[Book List] Update Book',
  props<{ update: Update<Book> }>()
);

export const deleteBook = createAction(
  '[Book List] Delete Book',
  props<{ id: string }>()
);

export const loadBooks = createAction(
  '[Book List] Load Books',
  props<{ books: Book[] }>()
);

Step 2: Dispatch Actions

Dispatch actions from your components to update the state:

import { Component } from '@angular/core';
import { Store } from '@ngrx/store';
import { Book } from './book.model';
import * as BookActions from './book.actions';

@Component({
  selector: 'app-book-list',
  templateUrl: './book-list.component.html',
})
export class BookListComponent {
  constructor(private store: Store) {}

  addBook(book: Book) {
    this.store.dispatch(BookActions.addBook({ book }));
  }

  updateBook(book: Book) {
    const update = {
      id: book.id,
      changes: book,
    };
    this.store.dispatch(BookActions.updateBook({ update }));
  }

  deleteBook(id: string) {
    this.store.dispatch(BookActions.deleteBook({ id }));
  }

  loadBooks(books: Book[]) {
    this.store.dispatch(BookActions.loadBooks({ books }));
  }
}

Step 3: Select Data

Use selectors to retrieve data from the store in your components:

import { Component, OnInit } from '@angular/core';
import { Store, select } from '@ngrx/store';
import { Observable } from 'rxjs';
import { Book } from './book.model';
import { selectAllBooks } from './book.selectors';

@Component({
  selector: 'app-book-list',
  templateUrl: './book-list.component.html',
})
export class BookListComponent implements OnInit {
  books$: Observable<Book[]>;

  constructor(private store: Store) {
    this.books$ = this.store.pipe(select(selectAllBooks));
  }

  ngOnInit() {
    // Load initial data or perform other initialization tasks
  }
}

Summary

In this module, we covered the basics of NgRx Entity, including how to set it up, define entity models, create reducers, and use selectors. NgRx Entity simplifies the management of collections in your Angular applications by providing a set of utilities for common operations. By following the steps outlined in this module, you can effectively manage entity collections in your NgRx store.

Next, we will explore more advanced state management techniques and how to integrate them into your Angular applications.

© Copyright 2024. All rights reserved