# 22. Use Entity Adapter

## 1. npm install @ngrx/entity

Entity State adapter for managing record collections. @ngrx/entity provides an API to manipulate and query entity collections.

1. Reduces boilerplate for creating reducers that manage a collection of models.
2. Provides performant CRUD operations for managing entity collections.
3. Extensible type-safe adapters for selecting entity information.

* npm install the library

```
npm i @ngrx/entity
```

## 2. Make an entity adapter&#x20;

* make an adapter and use it to make the initial state and manage collections.

{% code title="src/app/event/state/attendees/attendees.reducer.ts" %}

```typescript
<---------- ABBREVIATED CODE SNIPPET ---------->

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

import { AttendeesActions, AttendeesActionTypes } from './attendees.actions';
import { Attendee } from '../../../models';

export interface State extends EntityState<Attendee> {
  loading: boolean;
  error: any;
}

const adapter: EntityAdapter<Attendee> = createEntityAdapter<Attendee>();

export const intitalState: State = adapter.getInitialState({
  loading: false,
  error: null
});

export function reducer(state = intitalState, action: AttendeesActions): State {

<---------- ABBREVIATED CODE SNIPPET ---------->

```

{% endcode %}

## 3. Update reducer to use entity adapter collection methods

The entity adapter will allow us to take a collection and manage it with a set of Adapter Collection Methods. The entity adapter also provides methods for operations against an entity. These methods can change one to many records at a time. Each method returns the newly modified state if changes were made and the same state if no changes were made. You can read more here <https://github.com/ngrx/platform/blob/master/docs/entity/adapter.md>.

| Method     | Action                                              |
| ---------- | --------------------------------------------------- |
| addOne     | Add one entity to the collection                    |
| addMany    | Add multiple entities to the collection             |
| addAll     | Replace current collection with provided collection |
| removeOne  | Remove one entity from the collection               |
| removeAll  | Clear entity collection                             |
| updateOne  | Update one entity in the collectionaddOne           |
| updateMany | Update multiple entities in the collection          |
| upsertOne  | Add or Update one entity in the collection          |
| upsertMany | Add or Update multiple entities in the collection   |

* Change out manual collection management for adapter collection methods.
* Make selectors from the adapter with `adapter.getSelectors` method.

{% code title="src/app/event/state/attendees/attendees.reducer.ts" %}

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

import { AttendeesActions, AttendeesActionTypes } from './attendees.actions';
import { Attendee } from '../../../models';

export interface State extends EntityState<Attendee> {
  loading: boolean;
  error: any;
}

const adapter: EntityAdapter<Attendee> = createEntityAdapter<Attendee>();

export const intitalState: State = adapter.getInitialState({
  loading: false,
  error: null
});

export function reducer(state = intitalState, action: AttendeesActions): State {
  switch (action.type) {
    case AttendeesActionTypes.LoadAttendees: {
      return adapter.removeAll({
        ...state,
        loading: false,
        error: null
      });
    }

    case AttendeesActionTypes.LoadAttendeesSuccess: {
      return adapter.addAll(action.payload, {
        ...state,
        loading: false,
        error: null
      });
    }

    case AttendeesActionTypes.LoadAttendeesFail: {
      return adapter.removeAll({
        ...state,
        loading: false,
        error: action.payload
      });
    }

    default: {
      return state;
    }
  }
}

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


```

{% endcode %}

## 3. Update selectors

* Update attendee selectors to use the new adapter getSelector methods.

{% code title="src/app/event/state/attendees/attendees.selectors.ts" %}

```typescript
import { createFeatureSelector, createSelector } from '@ngrx/store';
import * as fromAttendee from './../attendees/attendees.reducer';
import { EventState } from '..';

export const getEventState = createFeatureSelector<EventState>('event');
export const getAttendeeState = createSelector(
  getEventState,
  state => state.attendees
);

export const getAttendees = createSelector(
  getAttendeeState,
  fromAttendee.selectAll
);

```

{% endcode %}

![Entity adapter making new ids and entities dictionaries.](/files/-LMI9DX6Bgfz4a1ZGDlp)

## StackBlitz Link

{% embed url="<https://stackblitz.com/github/duncanhunter/angular-and-ngrx-demo-app/tree/22-add-entity-adapter>" %}
Web Link: Link to the demo app running in StackBlitz
{% endembed %}


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://duncanhunter.gitbook.io/angular-and-ngrx/22.-use-entity-adapter.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
