The Complete Guide to CRUD Operations in Angular Using NgRx
Tags: angular, javascript, tutorial, typescript
Published: 2023-09-15 13:26:53

## Introduction
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dwd95dv4mya7izmyionk.png)

In modern web development, building responsive and data-driven applications is crucial. Angular, a powerful and widely-used JavaScript framework, provides the tools necessary to achieve this. When working with complex data management in Angular, NgRx is the go-to state management library. In this article, we'll explore how to implement CRUD (Create, Read, Update, Delete) operations in Angular using NgRx, following the MECE (Mutually Exclusive, Collectively Exhaustive) principle for a well-organized and efficient codebase.

## Table of Contents

1. What is NgRx?
2. Setting Up an Angular Project
3. Creating the NgRx Store
4. Implementing CRUD Operations
5. Handling Asynchronous Actions
6. Optimistic Updates for a Seamless User Experience
7. FAQ Section
8. Conclusion

## What is NgRx?

NgRx is a state management library for Angular applications that is inspired by the Redux pattern. It helps manage the complex state of your application by providing a unidirectional data flow. This makes it easier to reason about how data changes over time and facilitates the maintenance of large-scale applications.

## Setting Up an Angular Project

Before diving into NgRx and CRUD operations, let's set up an Angular project. If you haven't already installed Angular CLI, you can do so by running:

```markdown
npm install -g @angular/cli
```

Once Angular CLI is installed, create a new Angular project:

```markdown
ng new my-angular-app
```

Navigate to your project folder:

```markdown
cd my-angular-app
```

## Creating the NgRx Store

The heart of any NgRx application is the store, which holds the application's state. To create a store, you'll need to install NgRx packages:

```markdown
ng add @ngrx/store
```

Now, let's define the store structure by creating actions, reducers, and selectors. 

### Actions

Actions are plain JavaScript objects that represent unique events in your application. In a CRUD application, actions can be defined for creating, reading, updating, and deleting items. For instance:

```markdown
export const createItem = createAction('[Items] Create Item', props<{ item: Item }>());
export const updateItem = createAction('[Items] Update Item', props<{ item: Item }>());
export const deleteItem = createAction('[Items] Delete Item', props<{ id: string }>());
```

### Reducers

Reducers specify how the state should change in response to actions. They are pure functions that take the current state and an action as arguments and return a new state. Here's a basic example:

```markdown
const initialState: Item[] = [];

const itemsReducer = createReducer(
  initialState,
  on(createItem, (state, { item }) => [...state, item]),
  on(updateItem, (state, { item }) => state.map(existingItem => existingItem.id === item.id ? item : existingItem)),
  on(deleteItem, (state, { id }) => state.filter(item => item.id !== id))
);
```

### Selectors

Selectors allow you to access specific pieces of state from the store. They help keep your components decoupled from the store structure. For example:

```markdown
export const selectAllItems = createSelector(
  (state: AppState) => state.items,
  items => items
);
```

## Implementing CRUD Operations

Now that we have our store set up, let's implement CRUD operations in Angular.

### Create Operation

To create an item, dispatch the `createItem` action:

```markdown
this.store.dispatch(createItem({ item }));
```

### Read Operation

Reading items is straightforward using selectors. In your component, select the items:

```markdown
this.items$ = this.store.select(selectAllItems);
```

### Update Operation

Updating an item involves dispatching the `updateItem` action:

```markdown
this.store.dispatch(updateItem({ item }));
```

### Delete Operation

To delete an item, dispatch the `deleteItem` action:

```markdown
this.store.dispatch(deleteItem({ id }));
```

## Handling Asynchronous Actions

In real-world applications, data often comes from APIs, making asynchronous actions essential. NgRx provides the `@ngrx/effects` library to handle side effects like API calls.

### Effect for Fetching Data

Here's an example of how to fetch data asynchronously using NgRx effects:

```markdown
@Effect()
loadItems$ = this.actions$.pipe(
  ofType(loadItems),
  switchMap(() =>
    this.itemService.getItems().pipe(
      map(items => loadItemsSuccess({ items })),
      catchError(error => of(loadItemsFailure({ error })))
    )
  )
);
```

## Optimistic Updates for a Seamless User Experience

To enhance the user experience, you can implement optimistic updates. This means updating the UI immediately with the expected changes and then making the API call. If the API call fails, you can rollback the changes.

```markdown
// Dispatch the optimistic update
this.store.dispatch(updateItem({ item: updatedItem }));

// Make the API call
this.itemService.updateItem(updatedItem).subscribe(
  () => {
    // API call successful
  },
  () => {
    // API call failed, rollback the update
    this.store.dispatch(updateItem({ item: previousItem }));
  }
);
```

## FAQ Section

### Q1: Why use NgRx for state management in Angular?

**A1:** NgRx simplifies complex state management in Angular applications by providing a clear structure and a unidirectional data flow. It enhances code maintainability and scalability, making it an excellent choice for large-scale projects.

### Q2: Can I use NgRx with Angular CLI-generated projects?

**A2:** Yes, you can integrate NgRx with Angular CLI-generated projects seamlessly. Angular CLI provides commands for adding NgRx-related packages and generating boilerplate code.

### Q3: Are there any alternatives to NgRx for state management in Angular?

**A3:** Yes, there are alternatives like `ngx-store` and `ngxs`. However, NgRx is the most widely used and has a strong community and ecosystem support.

## Conclusion

In this comprehensive guide, we've explored how to implement CRUD operations in Angular using NgRx. We've covered the setup of NgRx, actions, reducers, selectors, and handling asynchronous actions with effects. Additionally, we've discussed the concept of optimistic updates to provide a smoother user experience. By following these guidelines and the MECE principle, you'll be well-equipped to build efficient and maintainable Angular applications with NgRx. Happy coding!