AppDividend
Latest Code Tutorials

Angular NGXS Tutorial With Example From Scratch

4,758

Get real time updates directly on you device, subscribe now.

Angular NGXS Tutorial With Example From Scratch is the today’s leading topic. We have covered the Angular NgRx Store pattern in this blog, and now it is time for an alternative to this library called Angular NGXS. Ngxs is a different approach to Angular state management. The official documentation for NGXS library is here.

If you want to learn more about Angular 7 then check out this Angular 7 – The complete Guide course.

#What is NGXS

NGXS is a state management pattern for the Angular framework. NGXS acts as a single source of truth for your application’s state, providing simple rules for predictable state mutations. The concept is same as a Redux library mostly used in React application. You can not directly change the state; you need to commit the action and then modify the state. NGXS is modeled after the CQRS pattern popularly implemented in libraries like Redux and NGRX but reduces boilerplate by using modern TypeScript features such as classes and decorators.

#Flow of NGXS

The flow of NGXS is effortless.

  1. Angular component dispatches the action.
  2. If the action needs to change the database values, then it sends a network request to the server and performs the database operations.
  3. Then after getting a response from the server, it will mutate the state. If the backend is not there, then action directly mutate the state of the store and component select that state and update the UI. It is the same cycle as Redux if you are familiar with it. You can find more on here.

Angular NGXS Tutorial With Example

We start this demo example by installing the Angular 6 using Angular CLI.

#Step 1: Install Angular.

If you have not previously installed Angular CLI globally on your machine, then install it using the following command.

npm install -g @angular/cli

# or

yarn add global @angular/cli

Create an Angular 6 project using the following command.

ng new ng6xs

 

Angular NGXS Tutorial With Example

Step 2: Install NGXS Store.

Next, we’ll install ngxs store.

yarn add @ngxs/store

 

Angular NGXS Store

Now install logger-plugin and devtools-plugin as a development dependency.

yarn add @ngxs/logger-plugin @ngxs/devtools-plugin --dev

Now, import these modules inside an app.module.ts file.

// app.module.ts

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { NgxsModule } from '@ngxs/store';
import { NgxsReduxDevtoolsPluginModule } from '@ngxs/devtools-plugin';
import { NgxsLoggerPluginModule } from '@ngxs/logger-plugin';

import { AppComponent } from './app.component';

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule,
    NgxsModule.forRoot(),
    NgxsReduxDevtoolsPluginModule.forRoot(),
    NgxsLoggerPluginModule.forRoot()
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

Type the following command to start the Angular Development server.

ng serve -o

 

NGXS Example in Angular

You can see the logs, so when the state changes, we can its old and new values.

Related Posts
1 of 16

Step 3: Create components.

Inside src >> app folder, create one folder called components.

Now, we will create and display the user information like name and email. We do not make a backend to store the user information. We need to add the data to the store and display data on the Angular Frontend.

We will create two components, so type the following command to generate the Angular components.

ng g c components/create --spec=false
ng g c components/index --spec=false

 

Angular NGXS Example

Also,  install the  Bootstrap 4 using the following command.

yarn add bootstrap

Now, add the following code inside src >> styles.css file.

@import "~bootstrap/dist/css/bootstrap.min.css"

Inside src >> app >> components >> create folder, we need to add some HTML code inside create.component.html file.

<div class="card">
  <div class="card-body">
    <form>
      <div class="form-group">
        <label class="col-md-4">Name</label>
        <input type="text" class="form-control" #name/>
      </div>
      <div class="form-group">
        <label class="col-md-4">Email</label>
        <input type="email" class="form-control" #email/>
        </div>
        <div class="form-group">
          <button (click)="addUser(name.value, email.value)" class="btn btn-primary">Create User</button>
        </div>
    </form>
  </div>
</div>

Now, add this component inside an app.component.html file.

<div class="container">
  <div class="row">
    <div class="col-md-6">
      <app-create></app-create>
    </div>
    <div class="col-md-6"></div>
  </div>
</div>

Save the file and go to the: http://localhost:4200/. You can see something like below.

NGXS State Management Library

 

Okay, now we need the ReactiveFormsModule. We will use the Reactive approach to the form and not template-driven approach. So Inside app.module.ts file, add the ReactiveFormsModule from @angular/forms package.

// app.module.ts

import { ReactiveFormsModule } from '@angular/forms';

 imports: [
    BrowserModule,
    NgxsModule.forRoot(),
    NgxsReduxDevtoolsPluginModule.forRoot(),
    NgxsLoggerPluginModule.forRoot(),
    ReactiveFormsModule
  ],

Now, write the following code inside a create.component.ts file.

// create.component.ts

import { Component, OnInit } from '@angular/core';
import { FormGroup, FormBuilder, Validators } from '@angular/forms';

@Component({
  selector: 'app-create',
  templateUrl: './create.component.html',
  styleUrls: ['./create.component.css']
})
export class CreateComponent implements OnInit {

  angForm: FormGroup;

  constructor(private fb: FormBuilder) {
    this.createForm();
  }

  createForm() {
    this.angForm = this.fb.group({
      name: ['', Validators.required ],
      email: ['', Validators.required ]
   });
  }

  addUser(name, email) {
    console.log(name, email);
  }

  ngOnInit() {
  }

}

And finally, write the html code inside a create.component.html file.

<div class="card">
  <div class="card-body">
    <form [formGroup]="angForm">
      <div class="form-group">
        <label class="col-md-4">Name</label>
        <input type="text" class="form-control" formControlName="name" #name/>
        <div *ngIf="angForm.controls['name'].invalid && (angForm.controls['name'].dirty || angForm.controls['name'].touched)" class="alert alert-danger">
          <div *ngIf="angForm.controls['name'].errors.required">
            Name is required.
          </div>
        </div>
      </div>
      <div class="form-group">
        <label class="col-md-4">Email</label>
        <input type="email" class="form-control" formControlName="email" #email/>
        <div *ngIf="angForm.controls['email'].invalid && (angForm.controls['email'].dirty || angForm.controls['email'].touched)" class="alert alert-danger">
          <div *ngIf="angForm.controls['email'].errors.required">
            Email is required.
          </div>
        </div>
      </div>
      <div class="form-group">
        <button (click)="addUser(name.value, email.value)" 
            class="btn btn-primary"
            [disabled]="angForm.pristine || angForm.invalid">Create User</button>
      </div>
    </form>
  </div>
</div>

#Step 4: Define model.

Inside src >> app folder, create one folder called models and inside that create one file called User.ts.

// User.ts

export interface User {
    name: string;
    email: string;
}

#Step 5: Define Actions.

We will create the addUser action. Inside src >> app folder, create one folder called actions. Inside actions folder, create one file called user.action.ts.

// user.action.ts

import { User } from '../models/User';

export class AddUser {
    static readonly type = '[User] Add';

    constructor(public payload: User) {}
}

#Step 6: Defining a State.

A key difference between Ngrx and Ngxs is how the state is handled. The state file in Ngxs takes the place of reducers in Ngrx. This is done by utilizing various decorators.

Inside src >> app folder, create one folder called state and in that folder, create one file called user.state.ts.

Write the following code inside the user.state.ts file.

// user.action.ts

import { State, Action, StateContext, Selector } from '@ngxs/store';
import { User } from '../models/User';
import { AddUser } from '../actions/user.action';

export class UserStateModel {
    users: User[];
}

@State<UserStateModel>({
    name: 'users',
    defaults: {
        users: []
    }
})
export class UserState {

    @Selector()
    static getUsers(state: UserStateModel) {
        return state.users;
    }

    @Action(AddUser)
    add({getState, patchState }: StateContext<UserStateModel>, { payload }: AddUser) {
        const state = getState();
        patchState({
            users: [...state.users, payload]
        });
    }
}

Here, we have defined the action to save the user data into the store. When the user tries to create the new user, we get those payload values here and add into the user’s state array. So, when the user is created, the store will update its user state and that state is fetched by another component. In our case it is index.component.ts. So it will change its UI and display the newly created user.

Finally, import the store inside a create.component.ts file.

// create.component.ts

import { Component, OnInit } from '@angular/core';
import { Store } from '@ngxs/store';
import { FormGroup, FormBuilder, Validators } from '@angular/forms';

import { AddUser } from '../../actions/user.action';

@Component({
  selector: 'app-create',
  templateUrl: './create.component.html',
  styleUrls: ['./create.component.css']
})
export class CreateComponent implements OnInit {

  angForm: FormGroup;

  constructor(private fb: FormBuilder, private store: Store) {
    this.createForm();
  }

  createForm() {
    this.angForm = this.fb.group({
      name: ['', Validators.required ],
      email: ['', Validators.required ]
   });
  }

  addUser(name, email) {
    this.store.dispatch(new AddUser({ name, email}));
  }

  ngOnInit() {
  }

}

#Step 7: Updating the app.module.ts file.

// user.state.ts

import { UserState } from './state/user.state';

imports: [
    BrowserModule,
    NgxsModule.forRoot([
      UserState
    ]),
    NgxsReduxDevtoolsPluginModule.forRoot(),
    NgxsLoggerPluginModule.forRoot(),
    ReactiveFormsModule
  ],

#Step 8: Display the data.

Write the following code inside the index.component.ts file.

// index.component.ts

import { Component, OnInit } from '@angular/core';
import { Store, Select } from '@ngxs/store';
import { User } from '../../models/User';
import { Observable } from 'rxjs';

@Component({
  selector: 'app-index',
  templateUrl: './index.component.html',
  styleUrls: ['./index.component.css']
})
export class IndexComponent implements OnInit {

  users: Observable<User>;

  constructor(private store: Store) {
    this.users = this.store.select(state => state.users.users);
   }

  ngOnInit() {
  }

}

Here, if the user’s state array is changed then this component rerenders and display the changes. For example, if the new user is added then this component rerenders and display the new user. 

Also, write the HTML code inside an index.component.html file.

<div *ngIf="users">
  <table class="table table-striped">
    <thead>
      <tr>
        <th>Name</th>
        <th>Email</th>
      </tr>
    </thead>
    <tbody>
      <tr *ngFor="let user of users | async">
        <td>{{ user.name }}</td>
        <td>{{ user.email }}</td>
      </tr>
    </tbody>
  </table>
</div>

Now, include this component inside an app.component.html file.

<div class="container">
  <div class="row">
    <div class="col-md-6">
      <app-create></app-create>
    </div>
    <div class="col-md-6">
      <app-index></app-index>
    </div>
  </div>
</div>

Save the file and go to the browser. You can see below.

Angular State Management Pattern

Finally, Angular NGXS Tutorial With Example is over. Thanks for taking.

Github Code

3 Comments
  1. That Guy says

    Thank you for the wonderful and detailed walkthrough

  2. scott lee says

    well explained tutorial, thanks
    1 suggestion : Starting Step 2, we should ‘cd ng6xs’ before running ‘yarn add @ngxs/store’

  3. Luis Castro says

    what about a full CRUD example?

Leave A Reply

Your email address will not be published.

This site uses Akismet to reduce spam. Learn how your comment data is processed.