State Management in Angular Using NGXS - Part 2
Tags: angular, programming, tutorial
Published: 2022-05-13 14:17:01

### 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.

### <br>

**TL;DR:** In the first part of the state management in Angular with NGXS series, we learned about the basics of NGXS, how it works, and how to use it to manage our application's state. In part 2, I will show you how to use Auth0 with NGXS to manage use-related states.

<hr/>

## User State Management

The user store will work similarly to how the menus state management works. I won't detail how each part of the state works and will focus more on the Auth0 and NGXS integration.

The starter app uses the Auth0 SDK directly and manages the roles through the `RolesService`. This tutorial section will walk you through migrating to using Auth0's SDK through NGXS and managing the roles by using the NGXS's `Select` function.

### Create user model

Let's start with defining the interface for the user state object. Open `user.model.ts` and add the following code 👇

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

import { User as Auth0User } from "@auth0/auth0-spa-js";

export interface UserStateModel {
  userDetails: Auth0User | undefined;
}
```

Create a barrel export for the `user` directory with the following code 👇

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

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

To further simplify our imports, add the user folder to the barrel export in the `state` folder and add the following code 👇

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

export * from "./menus";

// ✨ New 👇
export * from "./user";
```

### Create user actions

We have three user-related Actions that we need for our user Store. Login, logout, and user changed Action to keep the user details in our Store in sync with Auth0's SDK.

Since we have several user Actions that will originate from the Navbar component, you can group them under `AllNavbarAction` to ensure you aren't reusing these Actions in a different part of the application (following the Good Action Hygiene pattern).

Because the `UserChangedFromAuth0SDK` Action originates from Auth0's SDK, let's name the source part of the Action type as `Auth0 SDK`.

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

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

import { User as Auth0User } from "@auth0/auth0-spa-js";

export namespace User {
  export namespace AllNavbarActions {
    export class LoginFlowInitiated {
      static readonly type = "[Navbar] Login Flow Initiated";
    }

    export class LogoutFlowInitiated {
      static readonly type = "[Navbar] Logout Flow Initiated";
    }
  }
  export class UserChangedFromAuth0SDK {
    static readonly type = "[Auth0 SDK] User Changed";
    constructor(public payload: { user: Auth0User | undefined }) {}
  }
}
```

Add `user.actions` to the barrel export. Open `index.ts` and add the following code 👇

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

export * from "./user.model";

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

#### Update application to use user actions

Like what you did with menus-related functionalities in the first part of the article, let's update the application's user-related functionalities to use NGXS's Actions. You can use Actions by injecting the Store class and calling the `dispatch` function with the Action name you defined in the previous section.

Open `nav-bar.component.ts` and add the following code 👇

```typescript
// src/app/shared/components/nav-bar/nav-bar.component.ts

import { Component } from "@angular/core";
import { IconDefinition } from "@fortawesome/fontawesome-svg-core";
import { faHome, faUser, faUtensils } from "@fortawesome/free-solid-svg-icons";
import { AuthService } from "@auth0/auth0-angular";

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

export interface INavBarMenuLinkProps {
  to: string;
  icon: IconDefinition;
  label: string;
}

@Component({
  selector: "app-nav-bar",
  templateUrl: "./nav-bar.component.html",
  styleUrls: ["./nav-bar.component.scss"],
})
export class NavBarComponent {
  faUser = faUser;
  isAuthenticated$ = this.authService.isAuthenticated$;
  user$ = this.authService.user$;

  navOptions: INavBarMenuLinkProps[] = [
    { to: "/home", label: "Home", icon: faHome },
    { to: "/menu", label: "Menu", icon: faUtensils },
  ];

  constructor(
    private authService: AuthService,
    // ✨ New 👇
    private store: Store
  ) {}

  loginWithRedirect(): void {
    // ✨ New 👇
    this.store.dispatch(new User.AllNavbarActions.LoginFlowInitiated());
  }

  logout(): void {
    // ✨ New 👇
    this.store.dispatch(new User.AllNavbarActions.LogoutFlowInitiated());
  }
}
```

### Create user state

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

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

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

@State<UserStateModel>({
  name: "user",
  defaults: {
    userDetails: undefined,
  },
})
@Injectable()
export class UserState {}
```

Next, Let's add some utility Selectors for `user`, `isLoggedIn`, `userRoles`, and `isAdmin` to easily let your components access these properties. Open `user.state.ts` and update it with the following code 👇

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

import { Injectable } from "@angular/core";
import { UserStateModel } from "./user.model";

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

// ✨ New 👇
import { environment } from "src/environments/environment";

// ✨ New 👇
import { USER_ROLES } from "../../services";

@State<UserStateModel>({
  name: "user",
  defaults: {
    userDetails: undefined,
  },
})
@Injectable()
export class UserState {
  // ✨ New 👇
  @Selector()
  static user(state: UserStateModel) {
    return state.userDetails;
  }

  // ✨ New 👇
  @Selector()
  static isLoggedIn(state: UserStateModel) {
    return !!state.userDetails;
  }

  // ✨ New 👇
  @Selector()
  static userRoles(state: UserStateModel) {
    return (
      state.userDetails?.[`${environment.auth.audience}/roles`] || undefined
    );
  }

  // ✨ New 👇
  @Selector()
  static isAdmin(state: UserStateModel) {
    return state.userDetails?.[`${environment.auth.audience}/roles`]?.includes(
      USER_ROLES.MENU_ADMIN
    );
  }
}
```

Add `user.state` to the list of exports in `index.ts` 👇

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

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

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


[Read more...](https://auth0.com/blog/state-management-in-angular-with-ngxs-part-2/?utm_source=content_synd&utm_medium=sc&utm_campaign=angular)