---
title: "State Management in Angular Using NGXS"
description: "See how it's easy to manage your Angular application's state using NGXS and learn how you can use NGXS with Auth0's SDK to handle user-related functionalities."
authors:
  - name: "William Juan"
    url: "https://auth0.com/blog/authors/william-juan/"
date: "May 6, 2022"
category: "Developers,Tutorial,Angular"
tags: ["angular", "ngxs", "sdk"]
url: "https://auth0.com/blog/state-management-in-angular-with-ngxs-part-1/"
---

# State Management in Angular Using NGXS

## Intro

State management is a key component when building applications. There are various approaches by which we can manage the state in an Angular application, each with its pros and cons.

This blog post will focus on using NGXS as our state management solution. We will look at how you can use NGXS to manage your application's state by building a Recipe Admin Dashboard application. We will also learn how to secure the application using Auth0 and how it works with NGXS.

## What Is NGXS

[**NGXS**](https://www.ngxs.io/) is a state management pattern and library for Angular. NGXS acts 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 - a pattern implemented in state management libraries such as NgRx and Redux. NGXS combines this pattern with TypeScript's classes and decorators to create a state management library with minimal boilerplate.

## How Does NGXS Work

NGXS is made up of four main components - Store, Actions, State, and Select. These components create a unidirectional circular control flow from the component to the store (via Actions) and back to the component (via Selects). The diagram below shows how the control flows in NGXS.

![NGXS State Management Control Flow Diagram](https://images.ctfassets.net/23aumh6u8s0i/1MamGFzTw4qp4N0M1sU7rM/12823d598b1a171b1d0285cbc6650a4a/001_ngxs-how-it-works.png)

### Store

The **Store** in NGXS is a global state manager that dispatches actions to state containers and provides a way to select data slices out from the global state.

### Actions

**Actions** express unique events that happen in our application. Actions are how the application communicates with NGXS's Store to tell it what to do.

### State

**States** are classes that define a state container.

### Select

**Selects** in NGXS are functions that provide the ability to slice a specific portion of the state from the global state container.

## Prerequisites

Angular requires an [active LTS or maintenance LTS](https://nodejs.org/about/releases) version of Node.js. Angular applications also depend on [npm packages](https://docs.npmjs.com/getting-started/what-is-npm) for many features and functions. To download and install npm packages, you need an npm package manager such as [npm](https://docs.npmjs.com/cli/install) or [yarn](https://yarnpkg.com/).

This project has a server-side component that has to run in parallel when running the Frontend. Follow the instructions in the [Api Express Typescript Menu repo](https://github.com/auth0-cookbook/api_express_typescript_menu). You can read more about setting up the server-side with Auth0 in this [blog post](https://auth0.com/blog/node-js-and-typescript-tutorial-secure-an-express-api/).

This tutorial focuses on how to use Auth0 with NGXS. For more information on setting up Auth0 for Angular applications, follow the instructions on the [README](https://github.com/auth0-blog/spa_angular_typescript_dashboard/blob/main/README.md#register-a-client-application-with-auth0) or refer to this [blog post](https://auth0.com/blog/complete-guide-to-angular-user-authentication/#Connect-Angular-with-Auth0).

## Getting Started Quickly

I created a demo application with the basic structure and components to help you implement the NGXS-related part.

Clone the demo app and check out its starter branch:

```bash
git clone -b starter git@github.com:auth0-blog/spa_angular_typescript_dashboard.git
```

Once you clone the repo, make `spa_angular_typescript_dashboard` your current directory:

```bash
cd spa_angular_typescript_dashboard
```

Install the project's dependencies:

```bash
npm i
```

Run the project locally:

```bash
npm run start
```

> The starter project contains an admin dashboard with the ability to log in and log out using Auth0's SDK. The logged-in user can then view the dashboard and view, add, edit, and delete a menu item depending on the user's permissions.

## Devtools

You can use the [Redux devtools](https://github.com/zalmoxisus/redux-devtools-extension/) extension for Chrome or Firefox for debugging store-related operations.

To use this extension with NGXS, you'll need to add NGXS's devtools dependency to our project. You can do this using `npm`.

```bash
npm install @ngxs/devtools-plugin --save-dev
```

Import the `NgxsReduxDevtoolsPluginModule` in our `AppModule` and configure it based on your project's requirements. For this tutorial, you'll be using their default configuration. Open `app.module.ts` and add the following code 👇

```typescript
// src/app/app.module.ts

import { BrowserModule } from "@angular/platform-browser";
import { NgModule } from "@angular/core";
import { HttpClientModule, HTTP_INTERCEPTORS } from "@angular/common/http";
import { AuthHttpInterceptor, AuthModule } from "@auth0/auth0-angular";

// ✨ New 👇
import { NgxsReduxDevtoolsPluginModule } from "@ngxs/devtools-plugin";

import { AppRoutingModule } from "./app-routing.module";
import { AppComponent } from "./app.component";
import { NavBarModule } from "./shared";
import { environment } from "src/environments/environment";

@NgModule({
  imports: [
    BrowserModule,
    HttpClientModule,
    AuthModule.forRoot({
      ...environment.auth,
      cacheLocation: "localstorage",
      httpInterceptor: {
        allowedList: [
          `${environment.serverUrl}/api/menu/items`,
          `${environment.serverUrl}/api/menu/items/*`,
        ],
      },
    }),
    AppRoutingModule,
    NavBarModule,

    // ✨ New 👇
    environment.production ? [] : NgxsReduxDevtoolsPluginModule.forRoot(),
  ],
  declarations: [AppComponent],
  bootstrap: [AppComponent],
  providers: [
    {
      provide: HTTP_INTERCEPTORS,
      useClass: AuthHttpInterceptor,
      multi: true,
    },
  ],
})
export class AppModule {}
```

### Running the app and turning on devtools

After following the steps in this section, you should see an option to activate Redux devtools in your toolbar when you run the app. Once activated, you should see a window with an interface similar to the image below.

![Redux devtools with NGXS](https://images.ctfassets.net/23aumh6u8s0i/5BldaqgcD8fMrBJSwwub07/1e05e1ea78231bcd90108de241d1ce69/002_ngxs-redux-devtools.png)


> You can learn more about these features from their [official documentation](https://github.com/zalmoxisus/redux-devtools-extension).

## Install NGXS

You can use `npm` or `yarn` to install NGXS's dependencies.

Using `npm`

```bash
npm install @ngxs/store --save
```

Using `yarn`

```bash
yarn add @ngxs/store
```

> At the time this post was written, the latest NGXS store version was `3.7.2`, which will be the version we will be using throughout the tutorial.

## Architecture

The app's core is an admin dashboard where the logged-in user can add, edit, and delete a menu item. The logged-in user will perform all the operations or a subset of them depending on their permissions. You will use NGXS to manage the state updates and user/server-related events.

You will create two Stores for our application:

- _menus_: to manage menu related functionalities (CRUD operations)
- _user_: to manage user-related functionalities such as authentication using Auth0

You will also split the Store into three files - `.model.ts`, `.state.ts`, and `.action.ts` to make it easier to follow throughout the tutorial.

Let's first start by creating the following folder structure in our `core` directory (you will be updating each file as we discuss each section):

```
|- src/app/core
    |- state
        |- menus
            |- menus.actions.ts
            |- menus.model.ts
            |- menus.state.ts
            |- index.ts
        |- user
            |- user.actions.ts
            |- user.model.ts
            |- user.state.ts
            |- index.ts
        |- index.ts
```

> The starter app uses a `BehaviorSubject` in `menu-state.service.ts` to manage its state. This tutorial will walk you through migrating the `BehaviorSubject` based state management to NGXS.

## Menus State Management

### Create menus model

Let's start with creating the shape of the state object for menus. Open `menus.model.ts` and add the following code 👇

```typescript
// src/app/core/state/menus/menus.model.ts

import { MenuItem } from "../../models";

export interface MenusStateModel {
  menuItems: MenuItem[];
}
```

The interface `MenusStateModel` defines the type of object Menu's state will have.

Let's also create a barrel export in our `menus` folder. Create `index.ts` and add the following code 👇

```typescript
// src/app/core/state/menus/index.ts

export * from "./menus.model";
```

To further simplify our imports. Create another barrel export in the `state` folder and add the following code 👇

```typescript
// src/app/core/state/index.ts

export * from "./menus";
```

### Create menus action

Next, you will need to define what Actions you need to handle. We will be following the Good Action Hygiene principle when writing our Actions.

On a high level, Good Action Hygiene recommends thinking of Actions as events instead of commands. Instead of `addMenuItem` as the Action, use `addMenuItemFormSubmitted`. This pattern also encourages dispatching specific Action instead of reusing the same Action and including the source as part of the Action type. The image below shows the anatomy of an Action type.

![Anatomy of an Action name](https://images.ctfassets.net/23aumh6u8s0i/szxzeBUDPSelbpIeBntYH/80215fac23bbaafd968724c7deb44d4f/003_ngxs-good-action-hygiene.png)

Following this pattern makes it easier to debug as you have distinct Actions from each source. This lets you immediately know what event has just taken place and where it came from with a quick look at the devtools.

You can learn more about Good Action hygiene in this [blog post](https://indepth.dev/posts/1407/force-good-action-hygiene-and-write-less-actions-in-ngrx-with-the-prepared-events-pattern) by Sameera Perera and Mike Ryan's [talk](https://youtu.be/JmnsEvoy-gY) at ng-conf 2018.

Let's start with user-initiated Actions. This would include adding a new menu item, updating an existing menu item, and deleting a current menu item. Open `menus.actions.ts` and add the following code 👇

```typescript
// src/app/core/state/menus/menus.actions.ts

import { BaseMenuItem, MenuItem } from "../../models";

export namespace Menus {
  export class AddMenuItemFormSubmitted {
    static readonly type = "[Add Menu Page] Add Menu Item Form Submitted";
    constructor(public payload: { menuItem: BaseMenuItem }) {}
  }

  export class EditMenuItemFormSubmitted {
    static readonly type = "[Edit Menu Page] Edit Menu Item Form Submitted";
    constructor(public payload: { menuItem: MenuItem }) {}
  }

  export class DeleteMenuItemInitiated {
    static readonly type = "[Delete Menu Page] Delete Menu Item Initiated";
    constructor(public payload: { menuId: string }) {}
  }
}
```

You will need to fetch the menus from our API as the app load. Let's add an `appLoaded` Action that will be dispatched when the app loads. Open `menus.actions.ts` and add the following code 👇

```typescript
// src/app/core/state/menus/menus.actions.ts

import { BaseMenuItem, MenuItem } from "../../models";

export namespace Menus {
  // ✨ New 👇
  export class AppLoaded {
    static readonly type = "[App] App Loaded";
  }

  export class AddMenuItemFormSubmitted {
    static readonly type = "[Add Menu Page] Add Menu Item Form Submitted";
    constructor(public payload: { menuItem: BaseMenuItem }) {}
  }

  export class EditMenuItemFormSubmitted {
    static readonly type = "[Edit Menu Page] Edit Menu Item Form Submitted";
    constructor(public payload: { menuItem: MenuItem }) {}
  }

  export class DeleteMenuItemInitiated {
    static readonly type = "[Delete Menu Page] Delete Menu Item Initiated";
    constructor(public payload: { menuId: string }) {}
  }
}
```

Let's continue to other API-related Actions. Since calling an API could either succeed or fail, let's add success and fail handlers for each API-related Action.

> You could make success and error handling in several different ways. What I'm showing you is just one way you could do this.

Open `menus.actions.ts` and add the following code 👇

```typescript
// src/app/core/state/menus/menus.actions.ts

import { BaseMenuItem, MenuItem } from "../../models";

export namespace Menus {
  export class AppLoaded {
    static readonly type = "[App] App Loaded";
  }

  // ✨ New 👇
  export class FetchMenuSuccess {
    static readonly type = "[Menu API] Fetch Menu Success";
    constructor(public payload: { menuItems: MenuItem[] }) {}
  }

  // ✨ New 👇
  export class FetchMenuFailed {
    static readonly type = "[Menu API] Fetch Menu Failed";
    constructor(public payload: { error: any }) {}
  }

  export class AddMenuItemFormSubmitted {
    static readonly type = "[Add Menu Page] Add Menu Item Form Submitted";
    constructor(public payload: { menuItem: BaseMenuItem }) {}
  }

  // ✨ New 👇
  export class AddMenuItemSuccess {
    static readonly type = "[Menu API] Add Menu Item Success";
  }

  // ✨ New 👇
  export class AddMenuItemFailed {
    static readonly type = "[Menu API] Add Menu Item Failed";
    constructor(public payload: { error: any }) {}
  }

  export class EditMenuItemFormSubmitted {
    static readonly type = "[Edit Menu Page] Edit Menu Item Form Submitted";
    constructor(public payload: { menuItem: MenuItem }) {}
  }

  // ✨ New 👇
  export class EditMenuItemSuccess {
    static readonly type = "[Menu API] Edit Menu Item Success";
    constructor(public payload: { menuItem: MenuItem }) {}
  }

  // ✨ New 👇
  export class EditMenuItemFailed {
    static readonly type = "[Menu API] Edit Menu Item Failed";
    constructor(public payload: { error: any }) {}
  }

  export class DeleteMenuItemInitiated {
    static readonly type = "[Delete Menu Page] Delete Menu Item Initiated";
    constructor(public payload: { menuId: string }) {}
  }

  // ✨ New 👇
  export class DeleteMenuItemSuccess {
    static readonly type = "[Menu API] Delete Menu Item Success";
    constructor(public payload: { menuId: string }) {}
  }

  // ✨ New 👇
  export class DeleteMenuItemFailed {
    static readonly type = "[Menu API] Delete Menu Item Failed";
    constructor(public payload: { error: any }) {}
  }
}
```

Let's also add this to the barrel export. Open `index.ts` and add the following code:

```typescript
// src/app/core/state/menus/index.ts

export * from "./menus.model";

// ✨ New 👇
export * from "./menus.actions";
```

#### Update application to use menu actions

You will now update the current implementation in our application with these Actions for any state-related operations. You do this by injecting NGXS's `Store` in the component and calling its `dispatch` function with the Action you want to execute.

Starting with `appLoaded`, as this is called, when the application first loads. Since we will be making a call to the API that requires the auth token from the Auth0 SDK, let's wait for the Angular app to complete any pending process during initialization before dispatching this action. We can do this by listening to the `ApplicationRef`'s `isStable` property and dispatching the `AppLoaded` action when the observable returns its first `true`. Open `app.component.ts` and add the following code 👇

```typescript
// src/app/app.component.ts

import { ApplicationRef, Component } from "@angular/core";

// ✨ New 👇
import { Store } from "@ngxs/store";
import { first } from "rxjs/operators";
import { Menus } from "./core";

@Component({
  selector: "app-root",
  templateUrl: "./app.component.html",
  styleUrls: ["./app.component.scss"],
})
export class AppComponent {
  title = "spa-angular-typescript-dashboard";

  // ✨ New 👇
  constructor(private store: Store, private appRef: ApplicationRef) {
    this.appRef.isStable.pipe(first((stable) => stable)).subscribe(() => {
      this.store.dispatch(new Menus.AppLoaded());
    });
  }
}
```

Moving on to adding a menu item. Replace the `menuStateService`'s `addMenuItem` function with dispatching the `AddMenuItemFormSubmitted` action. Open `add-item.component.ts` and add the following code 👇

```typescript
// src/app/features/menu/add-item/add-item.component.ts

import { Component } from "@angular/core";
import { Location } from "@angular/common";

// ✨ New 👇
import { BaseMenuItem, Menus } from "src/app/core";
import { Store } from "@ngxs/store";

const MenuItemPlaceholder: BaseMenuItem = {
  name: "",
  price: 0,
  tagline: "",
  description: "",
  image: "",
  calories: 0,
  category: "",
};

@Component({
  selector: "app-add-item",
  templateUrl: "./add-item.component.html",
  styles: [
    `
      :host {
        width: 100%;
        height: 100%;
      }
    `,
  ],
})
export class AddItemComponent {
  menuItem = MenuItemPlaceholder;
  constructor(
    private location: Location,
    // ✨ New 👇
    private store: Store
  ) {}

  submit(menu: BaseMenuItem): void {
    // ✨ New 👇
    this.store.dispatch(
      new Menus.AddMenuItemFormSubmitted({
        menuItem: menu,
      })
    );
  }

  cancel(): void {
    this.location.back();
  }
}
```

Deleting a menu item. Replace the `menuStateService`'s `deleteMenuItem` function with dispatching the `DeleteMenuItemInitiated` action. Open `delete-item.component.ts` and add the following code 👇

```typescript
// src/app/features/menu/delete-item/delete-item.component.ts

import { Component } from "@angular/core";
import { Location } from "@angular/common";
import { ActivatedRoute, Router } from "@angular/router";
import { map, switchMap } from "rxjs/operators";

// ✨ New 👇
import { Menus, MenusStateService } from "src/app/core";
import { Store } from "@ngxs/store";

@Component({
  selector: "app-delete-item",
  templateUrl: "./delete-item.component.html",
  styleUrls: ["./delete-item.component.scss"],
})
export class DeleteItemComponent {
  menuItemId$ = this.activatedRoute.params.pipe(map((params) => params.id));
  menuItem$ = this.menuItemId$.pipe(
    switchMap((id) => this.menusStateService.selectMenuItem$(id))
  );

  constructor(
    private activatedRoute: ActivatedRoute,
    private location: Location,
    private router: Router,
    private menusStateService: MenusStateService,
    // ✨ New 👇
    private store: Store
  ) {}

  deleteMenuItem(id: string): void {
    // ✨ New 👇
    this.store.dispatch(
      new Menus.DeleteMenuItemInitiated({
        menuId: id,
      })
    );
  }

  cancel(): void {
    this.back();
  }

  back(): void {
    this.location.back();
  }

  navigateHome(): void {
    this.router.navigate(["/menu"]);
  }
}
```

Editing an existing menu item. Replace the `menuStateService`'s `editMenuItem` function with dispatching the `EditMenuItemFormSubmitted` action. Open `edit-item.component.ts` and add the following code 👇

```typescript
// src/app/features/menu/edit-item/edit-item.component.ts

import { Component } from "@angular/core";
import { Location } from "@angular/common";
import { ActivatedRoute } from "@angular/router";
import { map, switchMap, tap } from "rxjs/operators";

// ✨ New 👇
import { BaseMenuItem, Menus, MenusStateService } from "src/app/core";
import { Store } from "@ngxs/store";

@Component({
  selector: "app-edit-item",
  templateUrl: "./edit-item.component.html",
  styles: [
    `
      :host {
        width: 100%;
        height: 100%;
      }
    `,
  ],
})
export class EditItemComponent {
  menuItemId$ = this.activatedRoute.params.pipe(map((params) => params.id));
  menuItem$ = this.menuItemId$.pipe(
    tap((id) => (this.id = id)),
    switchMap((id) =>
      this.menusStateService.selectMenuItem$(id).pipe(
        map((menuItem) => {
          return <BaseMenuItem>{
            ...menuItem,
            price:
              menuItem && menuItem.price > 0
                ? (menuItem.price / 100).toFixed(2)
                : 0,
          };
        })
      )
    )
  );

  private id: number | undefined;

  constructor(
    private activatedRoute: ActivatedRoute,
    private location: Location,
    private menusStateService: MenusStateService,
    // ✨ New 👇
    private store: Store
  ) {}

  cancel(): void {
    this.location.back();
  }

  submit(menu: BaseMenuItem): void {
    if (!this.id) {
      return;
    }
    // ✨ New 👇
    this.store.dispatch(
      new Menus.EditMenuItemFormSubmitted({
        menuItem: {
          ...menu,
          id: this.id.toString(),
        },
      })
    );
  }
}
```

### Create menus state

Before creating individual selectors for slices of the menu state, let's start by creating the boilerplate required to use this feature. NGXS uses an `Injectable` class with an additional `State` decorator. Open `menus.state.ts` and add the following code 👇

```typescript
// src/app/core/state/menus/menus.state.ts

import { Injectable } from "@angular/core";
import { State } from "@ngxs/store";
import { MenusStateModel } from "./menus.model";

@State<MenusStateModel>({
  name: "menus",
  defaults: {
    menuItems: [],
  },
})
@Injectable()
export class MenusState {}
```

You can use NGXS's `Selector` decorator to select slices of the state. For menus, you only have one entry in our object, which is `menuItems`. Let's create a function with NGXS's `Selector` decorator to access the `menuItems` property. Open `menus.state.ts` and update it with the following code 👇

```typescript
// src/app/core/state/menus/menus.state.ts

import { Injectable } from "@angular/core";

// ✨ New 👇
import { State, Selector } from "@ngxs/store";
import { MenusStateModel } from "./menus.model";

@State<MenusStateModel>({
  name: "menus",
  defaults: {
    menuItems: [],
  },
})
@Injectable()
export class MenusState {
  // ✨ New 👇
  @Selector()
  static menus(state: MenusStateModel) {
    return state;
  }

  // ✨ New 👇
  @Selector()
  static menuItems(state: MenusStateModel) {
    return state.menuItems;
  }
}
```

For pages like _Menu Details_, _Edit Menu_, and _Delete Menu_, you'll need to access a specific menu item from the Store. You can do this by creating a function that accepts the menu id as a parameter and searches through our array of menu items from the `menuItems` selector. Open `menus.state.ts` and add the following code 👇

```typescript
// src/app/core/state/menus/menus.state.ts

import { Injectable } from "@angular/core";

// ✨ New 👇
import { State, Selector, createSelector } from "@ngxs/store";
import { MenusStateModel } from "./menus.model";

@State<MenusStateModel>({
  name: "menus",
  defaults: {
    menuItems: [],
  },
})
@Injectable()
export class MenusState {
  @Selector()
  static menus(state: MenusStateModel) {
    return state;
  }

  @Selector()
  static menuItems(state: MenusStateModel) {
    return state.menuItems;
  }

  // ✨ New 👇
  static menuItem(id: string) {
    return createSelector([MenusState], (state: MenusStateModel) => {
      return state.menuItems.find((menuItem) => menuItem.id === id);
    });
  }
}
```

Let's also add the `menus.state.ts` file to the barrel export. Open `index.ts` and add the following code 👇

```typescript
// src/app/core/state/menus/index.ts

export * from "./menus.model";
export * from "./menus.actions";

// ✨ New 👇
export * from "./menus.state";
```

#### Update application to use menus selectors

Similar to what you did with Actions, let's update the application to get data required by the components using NGXS's selectors. You can use selectors by injecting the Store class and calling the `select` function with the selector names you defined in the previous section.

Starting with the main dashboard, open `menu-items.component.ts` and add the following code 👇

```typescript
// src/app/features/menu/menu-items/menu-items.component.ts

import { Component } from "@angular/core";
import { ActivatedRoute, Router } from "@angular/router";
import { RolesService } from "src/app/core";

// ✨ New 👇
import { Store } from "@ngxs/store";
import { MenusState } from "src/app/core";

@Component({
  selector: "app-menu-items",
  templateUrl: "./menu-items.component.html",
  styles: [
    `
      :host {
        width: 100%;
        height: 100%;
      }
    `,
  ],
})
export class MenuItemsComponent {
  // ✨ New 👇
  menuItems$ = this.store.select(MenusState.menuItems);
  isAdmin$ = this.rolesService.isAdmin$;

  constructor(
    private router: Router,
    private activatedRoute: ActivatedRoute,
    private rolesService: RolesService,
    // ✨ New 👇
    private store: Store
  ) {}

  addMenuItem(): void {
    this.router.navigate(["add"], { relativeTo: this.activatedRoute });
  }
}
```

Moving on to the _Menu Details_ page. Here, we only need a specific menu's data. Instead of using the `selectMenuItems`, you will use NGXS's `select` function passing in `MenusState.menuItem` with the menu id from the route parameters. Open `menu-item.component.ts` and add the following code 👇

```typescript
// src/app/features/menu/menu-item/menu-item.component.ts

import { Component } from "@angular/core";
import { Location } from "@angular/common";
import { ActivatedRoute, Router } from "@angular/router";
import { map, switchMap } from "rxjs/operators";
import { RolesService } from "src/app/core";

// ✨ New 👇
import { Store } from "@ngxs/store";
import { MenusState } from "src/app/core";

@Component({
  selector: "app-menu-item",
  templateUrl: "./menu-item.component.html",
  styleUrls: ["./menu-item.component.scss"],
})
export class MenuItemComponent {
  menuItemId$ = this.activatedRoute.params.pipe(map((params) => params.id));

  // ✨ New 👇
  menuItem$ = this.menuItemId$.pipe(
    switchMap((id) => this.store.select(MenusState.menuItem(id)))
  );
  isAdmin$ = this.rolesService.isAdmin$;

  constructor(
    private activatedRoute: ActivatedRoute,
    private router: Router,
    private location: Location,
    private rolesService: RolesService,
    // ✨ New 👇
    private store: Store
  ) {}

  back(): void {
    this.location.back();
  }

  navigateTo(url: string): void {
    this.router.navigateByUrl(`${this.router.url}/${url}`);
  }
}
```

_Delete Menu Item_ page, open `delete-item.component.ts`, and add the following code 👇

```typescript
// src/app/features/menu/delete-item/delete-item.component.ts

import { Component } from "@angular/core";
import { Location } from "@angular/common";
import { ActivatedRoute, Router } from "@angular/router";
import { map, switchMap } from "rxjs/operators";
import { Store } from "@ngxs/store";

// ✨ New 👇
import { Menus, MenusState } from "src/app/core";

@Component({
  selector: "app-delete-item",
  templateUrl: "./delete-item.component.html",
  styleUrls: ["./delete-item.component.scss"],
})
export class DeleteItemComponent {
  menuItemId$ = this.activatedRoute.params.pipe(map((params) => params.id));

  // ✨ New 👇
  menuItem$ = this.menuItemId$.pipe(
    switchMap((id) => this.store.select(MenusState.menuItem(id)))
  );

  constructor(
    private activatedRoute: ActivatedRoute,
    private location: Location,
    private router: Router,
    // ✨ New 👇
    private store: Store
  ) {}

  deleteMenuItem(id: string): void {
    this.store.dispatch(
      new Menus.DeleteMenuItemInitiated({
        menuId: id,
      })
    );
  }

  cancel(): void {
    this.back();
  }

  back(): void {
    this.location.back();
  }

  navigateHome(): void {
    this.router.navigate(["/menu"]);
  }
}
```

And finally, _Edit Menu Item_ page. Open `edit-item.component.ts` and add the following code 👇

```typescript
// src/app/features/menu/edit-item/edit-item.component.ts

import { Component } from "@angular/core";
import { Location } from "@angular/common";
import { ActivatedRoute } from "@angular/router";
import { map, switchMap, tap } from "rxjs/operators";
import { Store } from "@ngxs/store";

// ✨ New 👇
import { BaseMenuItem, Menus, MenusState } from "src/app/core";

@Component({
  selector: "app-edit-item",
  templateUrl: "./edit-item.component.html",
  styles: [
    `
      :host {
        width: 100%;
        height: 100%;
      }
    `,
  ],
})
export class EditItemComponent {
  menuItemId$ = this.activatedRoute.params.pipe(map((params) => params.id));

  // ✨ New 👇
  menuItem$ = this.menuItemId$.pipe(
    tap((id) => (this.id = id)),
    switchMap((id) =>
      this.store.select(MenusState.menuItem(id)).pipe(
        map((menuItem) => {
          return <BaseMenuItem>{
            ...menuItem,
            price:
              menuItem && menuItem.price > 0
                ? (menuItem.price / 100).toFixed(2)
                : 0,
          };
        })
      )
    )
  );

  private id: number | undefined;

  constructor(
    private activatedRoute: ActivatedRoute,
    private location: Location,
    // ✨ New 👇
    private store: Store
  ) {}

  cancel(): void {
    this.location.back();
  }

  submit(menu: BaseMenuItem): void {
    if (!this.id) {
      return;
    }
    this.store.dispatch(
      new Menus.EditMenuItemFormSubmitted({
        menuItem: {
          ...menu,
          id: this.id.toString(),
        },
      })
    );
  }
}
```

### Create menus action handlers

Our states listen to actions via an `Action` decorator. The action decorator accepts an action class or an array of action classes. When an action that matches the action in the decorator is dispatched, the function attached to the decorator will get executed.

For the Menus state, action handlers will be used to make an HTTP request to get data from the server or perform other CRUD operations. In addition to the API calls, we will also be using the action handlers to update our state object.

Let's start with a simple action handler that handles fetching the menu items from the API and updating the store with new data. Since this logic needs to be executed when the app loads and a new menu item is added successfully, you will pass in two actions to the action decorator - `Menus.AppLoaded` and `Menus.AddMenuItemSuccess`. You will then return the `apiService.getItems` function to get the menu items. If it's successful, dispatch the `FecthMenuSuccess` action with the menu items returned from the API, which will update the store with this new data. If unsuccessful, it will jump to the `catchError` block, which dispatches the `FetchMenuFailed` action with the error thrown. `FetchMenuSuccess` will then update the state object with the new menu items returned by the API call.

![Diagram of how the fetch menu action works](https://images.ctfassets.net/23aumh6u8s0i/7GUTVHchrTEDs8VV7G6SFn/42b7d0f606302b2eddddf5151e0c366e/004_ngxs-fetch-menu.png)

> Tip: add your `catchError` to the inner observable in your `switchMap` instead of on the main observable to prevent the action stream from being closed when an error is thrown

Open `menus.state.ts` and add the following code 👇

```typescript
// src/app/core/state/menus/menus.state.ts

import { Injectable } from "@angular/core";
import { of } from "rxjs";
import { catchError, map } from "rxjs/operators";
import { MenusStateModel } from "./menus.model";

// ✨ New 👇
import {
  State,
  Action,
  StateContext,
  Selector,
  createSelector,
} from "@ngxs/store";
import { Menus } from "./menus.actions";
import { ApiService } from "../../services";
import { MenuItem } from "../../models";

@State<MenusStateModel>({
  name: "menus",
  defaults: {
    menuItems: [],
  },
})
@Injectable()
export class MenusState {
  // ✨ New 👇
  constructor(private apiService: ApiService) {}

  // ✨ New 👇
  @Action([Menus.AppLoaded, Menus.AddMenuItemSuccess])
  fetchMenu(ctx: StateContext<MenusStateModel>) {
    return this.apiService.getItems().pipe(
      map((menuItems: MenuItem[]) => {
        return ctx.dispatch(
          new Menus.FetchMenuSuccess({
            menuItems: menuItems,
          })
        );
      }),
      catchError((error) => {
        return of(
          ctx.dispatch(
            new Menus.FetchMenuFailed({
              error: error,
            })
          )
        );
      })
    );
  }

  // ✨ New 👇
  @Action(Menus.FetchMenuSuccess)
  fetchMenuSuccess(
    ctx: StateContext<MenusStateModel>,
    action: Menus.FetchMenuSuccess
  ) {
    const state = ctx.getState();
    ctx.setState({
      ...state,
      menuItems: action.payload.menuItems,
    });
  }

  @Selector()
  static menus(state: MenusStateModel) {
    return state;
  }

  @Selector()
  static menuItems(state: MenusStateModel) {
    return state.menuItems;
  }

  // dynamic selector with arguments
  static menuItem(id: string) {
    return createSelector([MenusState], (state: MenusStateModel) => {
      return state.menuItems.find((menuItem) => menuItem.id === id);
    });
  }
}
```

Following the same logic, let's create action handlers for `AddMenu`, `EditMenu`, and `DeleteMenu` along with their success handlers to update the state object. Open `menus.state.ts` and update it with the following code 👇

```typescript
// src/app/core/state/menus/menus.state.ts

// ✨ New 👇
import { Injectable, NgZone } from "@angular/core";
import { Router } from "@angular/router";
import { Location } from "@angular/common";

import { of } from "rxjs";
import { tap, catchError, map } from "rxjs/operators";
import {
  State,
  Action,
  StateContext,
  Selector,
  createSelector,
} from "@ngxs/store";
import { MenusStateModel } from "./menus.model";
import { ApiService } from "../../services";
import { Menus } from "./menus.actions";
import { MenuItem } from "../../models";

@State<MenusStateModel>({
  name: "menus",
  defaults: {
    menuItems: [],
  },
})
@Injectable()
export class MenusState {
  constructor(
    // ✨ New 👇
    private location: Location,
    private zone: NgZone,
    private router: Router,
    private apiService: ApiService
  ) {}

  @Action([Menus.AppLoaded, Menus.AddMenuItemSuccess])
  fetchMenu(ctx: StateContext<MenusStateModel>) {
    return this.apiService.getItems().pipe(
      map((menuItems: MenuItem[]) => {
        return ctx.dispatch(
          new Menus.FetchMenuSuccess({
            menuItems: menuItems,
          })
        );
      }),
      catchError((error) => {
        return of(
          ctx.dispatch(
            new Menus.FetchMenuFailed({
              error: error,
            })
          )
        );
      })
    );
  }

  @Action(Menus.FetchMenuSuccess)
  fetchMenuSuccess(
    ctx: StateContext<MenusStateModel>,
    action: Menus.FetchMenuSuccess
  ) {
    const state = ctx.getState();
    ctx.setState({
      ...state,
      menuItems: action.payload.menuItems,
    });
  }

  // ✨ New 👇
  @Action(Menus.AddMenuItemFormSubmitted)
  addMenuItem(
    ctx: StateContext<MenusStateModel>,
    action: Menus.AddMenuItemFormSubmitted
  ) {
    return this.apiService.addItem(action.payload.menuItem).pipe(
      tap(() => {
        this.zone.run(() => {
          this.router.navigate(["/menu"]);
        });
      }),
      map(() => {
        return ctx.dispatch(new Menus.AddMenuItemSuccess());
      }),
      catchError((error) => {
        return of(ctx.dispatch(new Menus.AddMenuItemFailed({ error: error })));
      })
    );
  }

  // ✨ New 👇
  @Action(Menus.EditMenuItemFormSubmitted)
  editMenuItem(
    ctx: StateContext<MenusStateModel>,
    action: Menus.EditMenuItemFormSubmitted
  ) {
    const menuItem = action.payload.menuItem;
    return this.apiService.updateItem(menuItem).pipe(
      tap(() => this.location.back()),
      map(() => {
        return ctx.dispatch(
          new Menus.EditMenuItemSuccess({
            menuItem: action.payload.menuItem,
          })
        );
      }),
      catchError((error) => {
        return of(ctx.dispatch(new Menus.EditMenuItemFailed({ error: error })));
      })
    );
  }

  // ✨ New 👇
  @Action(Menus.EditMenuItemSuccess)
  editMenuSuccess(
    ctx: StateContext<MenusStateModel>,
    action: Menus.EditMenuItemSuccess
  ) {
    const state = ctx.getState();
    const menuItem = action.payload.menuItem;
    const menuItemIndex = state.menuItems.findIndex(
      (item) => item.id === menuItem.id
    );
    const updatedMenuItems = [...state.menuItems];
    updatedMenuItems[menuItemIndex] = menuItem;
    ctx.setState({
      ...state,
      menuItems: updatedMenuItems,
    });
  }

  // ✨ New 👇
  @Action(Menus.DeleteMenuItemInitiated)
  deleteMenuItem(
    ctx: StateContext<MenusStateModel>,
    action: Menus.DeleteMenuItemInitiated
  ) {
    const menuId = action.payload.menuId;
    return this.apiService.deleteItem(menuId).pipe(
      tap(() => {
        this.zone.run(() => {
          this.router.navigate(["/menu"]);
        });
      }),
      map(() => {
        return ctx.dispatch(
          new Menus.DeleteMenuItemSuccess({ menuId: menuId })
        );
      }),
      catchError((error) => {
        return of(
          ctx.dispatch(new Menus.DeleteMenuItemFailed({ error: error }))
        );
      })
    );
  }

  // ✨ New 👇
  @Action(Menus.DeleteMenuItemSuccess)
  deleteMenuSuccess(
    ctx: StateContext<MenusStateModel>,
    action: Menus.DeleteMenuItemSuccess
  ) {
    const state = ctx.getState();
    const menuId = action.payload.menuId;
    const menuItemIndex = state.menuItems.findIndex(
      (item) => item.id === menuId
    );
    const updatedMenuItems = [...state.menuItems];
    updatedMenuItems.splice(menuItemIndex, 1);
    ctx.setState({
      ...state,
      menuItems: updatedMenuItems,
    });
  }

  @Selector()
  static menus(state: MenusStateModel) {
    return state;
  }

  @Selector()
  static menuItems(state: MenusStateModel) {
    return state.menuItems;
  }

  // dynamic selector with arguments
  static menuItem(id: string) {
    return createSelector([MenusState], (state: MenusStateModel) => {
      return state.menuItems.find((menuItem) => menuItem.id === id);
    });
  }
}
```

#### Configure NGXS's store module

You will then need to initialize NGXS's `StoreModule` passing in all your feature states (in our case, just the `MenusState` for now). Open `app.module.ts` and add the following code 👇

```typescript
// src/app/app.module.ts

import { BrowserModule } from "@angular/platform-browser";
import { NgModule } from "@angular/core";
import { AuthHttpInterceptor, AuthModule } from "@auth0/auth0-angular";

import { AppRoutingModule } from "./app-routing.module";
import { AppComponent } from "./app.component";
import { NavBarModule } from "./shared";
import { environment } from "src/environments/environment";
import { HttpClientModule, HTTP_INTERCEPTORS } from "@angular/common/http";
import { NgxsReduxDevtoolsPluginModule } from "@ngxs/devtools-plugin";

// ✨ New 👇
import { NgxsModule } from "@ngxs/store";
import { MenusState } from "./core";

@NgModule({
  imports: [
    BrowserModule,
    HttpClientModule,
    AuthModule.forRoot({
      ...environment.auth,
      cacheLocation: "localstorage",
      httpInterceptor: {
        allowedList: [
          `${environment.serverUrl}/api/menu/items`,
          `${environment.serverUrl}/api/menu/items/*`,
        ],
      },
    }),
    AppRoutingModule,
    NavBarModule,

    // ✨ New 👇
    NgxsModule.forRoot([MenusState], { developmentMode: true }),

    NgxsReduxDevtoolsPluginModule.forRoot(),
  ],
  declarations: [AppComponent],
  bootstrap: [AppComponent],
  providers: [
    {
      provide: HTTP_INTERCEPTORS,
      useClass: AuthHttpInterceptor,
      multi: true,
    },
  ],
})
export class AppModule {}
```

> **Checkpoint:** Executing any CRUD operations such as adding a new menu item and editing or deleting an existing menu item should make an API call to update the server's database and also update the app's state. Only authenticated users with a `menu-admin` role can create, update, and delete menu items. The `menu-admin` role bundles the necessary permissions to execute these write operations. Read more on how to configure role-based access control (RBAC) and how to create an admin user for this application in this [blog post](https://auth0.com/blog/node-js-and-typescript-tutorial-secure-an-express-api/#Configure-Role-Based-Access-Control--RBAC-)

## Conclusion

We've covered how NGXS works, its installation, and how to use it to manage our application's state. In the second half of this tutorial: [State Management in Angular with NGXS - Part 2](https://auth0.com/blog/state-management-in-angular-with-ngxs-part-2/), we'll learn how to use Auth0 with NGXS to manage user-related states.
