NgRx Course – Sample Application Setup

The last video introduced NgRx and we saw how to add @ngrx/store to an Angular application. In this video, we’re going to see the sample application that we’ll be building during the rest of this course. We will also create the initial setup.

The video shows that it is a simple application to manage some items or customers in this case. The customers component is loaded using lazy loading.

The application is communicating with an API, it’s fetching or reading some initial data from the server. We’re able to create or add new items. And we can also edit or update the items and we can remove or delete items from the list.

However, the application will create some side effects when we interact with the server. So, we manage those side effects with the NgRx/effect library.

It is a basic CRUD application that communicates with a back-end server and implements a store.

In this part, we’re going to create the folder structure for our project. We’re going to build the main components, the router, and the service. And we will also set up the customers module for lazy loading.

We’re going to be using json-server to simulate an API and you can install it using the following command:

$ npm install -g json-server

After we have installed it we have to add a db.json file in our application folder that will contain the initial data and be used as a server. And you can create this by pasting the following inside:

// db.json
{
  "customers": [
    {
      "name": "John Doe",
      "phone": "910928392098",
      "address": "123 Sun Street",
      "membership": "Platinum",
      "id": 1
    },
    {
      "name": "Mary Johnson",
      "phone": "808937482734",
      "address": "893 Main Voulevard",
      "membership": "Pro",
      "id": 2
    }
  ]
}

Now, we can go and modify the scripts in our package.json file to run the server concurrently with the angular application:

  // package.json
   …
   "scripts": {
    "ng": "ng",
    "start": "concurrently \"ng serve\" \"json-server --watch db.json\" ",
    "build": "ng build",
    "test": "ng test",
    "lint": "ng lint",
    "e2e": "ng e2e"
  },
  …

We want to run both the angular application and the json-server at the same time. To do this we also need to install the concurrent package:

$ npm install concurrently

And now you’ll be able to run the application and the API with the command:

$ npm run start

Let’s create the basic structure and components for our project. First, we’re going to add the bootstrap CSS file in the index.html to have some nice styling by default. And now add the following line to the index.html file:

// index.html
<link rel="stylesheet" href="https://bootswatch.com/4/yeti/bootstrap.css">

Now we’re going to create the home component and the navbar component using the Angular CLI:

$ ng g c home
$ ng g c navbar

And for the customers, we’re going to organize the application by features with lazy loaded modules. Let’s create a folder called customers for the module and the child components using the Angular CLI:

$ ng g m customers
$ ng g c customers/customer  -m customers
$ ng g c customers/customer-add  -m customers
$ ng g c customers/customer-edit  -m customers
$ ng g c customers/customer-list  -m customers

We now have the main components, we’re going to create the app-routing module.

$ ng g m app-routing –flat

And add the AppRoutingModule to the app.module.ts file:

// app.module.ts
import { BrowserModule } from "@angular/platform-browser";
import { NgModule } from "@angular/core";

// NgRx
import { StoreModule } from "@ngrx/store";

import { AppRoutingModule } from "./app-routing.module";

import { AppComponent } from "./app.component";
import { HomeComponent } from "./home/home.component";
import { NavbarComponent } from "./navbar/navbar.component";

@NgModule({
  declarations: [AppComponent, HomeComponent, NavbarComponent],
  imports: [
    BrowserModule,
    // Import Store module
    StoreModule.forRoot({}),
    AppRoutingModule
  ],
 export class AppModule {}

Define the routes in the app-routing module:

// app-routing.module.ts
import { NgModule } from "@angular/core";
import { CommonModule } from '@angular/common';
import { RouterModule, Routes } from "@angular/router";

import { HomeComponent } from "./home/home.component";

const appRoutes: Routes = [
  { path: "", component: HomeComponent },
  {
    path: "customers",
    loadChildren: "../app/customers/customer.module#CustomerModule"
  }
];

@NgModule({
  imports: [RouterModule.forRoot(appRoutes)],
  exports: [RouterModule],
  declarations: []
})

export class AppRoutingModule {}

Add the routes to the customers.module.ts module :

// customers/customers.module.ts
import { NgModule } from "@angular/core";
import { CommonModule } from "@angular/common";
import { RouterModule, Routes } from "@angular/router";

import { CustomerComponent } from "./customer/customer.component";
import { CustomerAddComponent } from "./customer-add/customer-add.component";
import { CustomerEditComponent } from "./customer-edit/customer-edit.component";
import { CustomerListComponent } from "./customer-list/customer-list.component";

// Routes
const customerRoutes: Routes = [{ path: "", component: CustomerComponent }];

@NgModule({
  imports: [CommonModule, RouterModule.forChild(customerRoutes)],
  declarations: [
    CustomerComponent,
    CustomerAddComponent,
    CustomerEditComponent,
    CustomerListComponent
  ]
})
export class CustomersModule {}

To make the router work in our application, add the router-outlet tag to the app.component.html file. And we also add the navbar now that we’re here:

// app.component.ts
<app-navbar></app-navbar>
<router-outlet></router-outlet>

To start building the components, we’re going to add some initial HTML to our files.

home.component.ts:

// home.component.html
<div class="container">
  <div class="jumbotron">
    <h1 class="display-4">Welcome</h1>
    <p class="lead">Please seldct your option below</p>
    <hr class="my-4">
    <p class="lead">
      <a class="btn btn-primary btn-lg" [routerLink]="['customers']" role="button">Customers</a>
    </p>
  </div>
</div>

navbar.component.ts:

// navbar.component.ts
<nav class="navbar navbar-expand-lg navbar-dark bg-primary mb-5">
  <a class="navbar-brand" [routerLink]="['/']">NGRX</a>
  <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent" aria-controls="navbarSupportedContent"
    aria-expanded="false" aria-label="Toggle navigation">
    <span class="navbar-toggler-icon"></span>
  </button>
  <div class="collapse navbar-collapse" id="navbarSupportedContent">
    <ul class="navbar-nav mr-auto">
      <li class="nav-item active">
        <a class="nav-link" [routerLink]="['/customers']">Customers</a>
      </li>
    </ul>
    <ul class="navbar-nav ml-auto">
    </ul>
  </div>
</nav>

customer.component.html:

// customers/customer.component.ts
<div class="container">
  <app-customer-add></app-customer-add>
  <app-customer-list></app-customer-list>
  <app-customer-edit></app-customer-edit>
</div>

customer-add.component.html:

// customers/customer-add.component.ts
<h3>Add Customer</h3>

<form class="form-inline mb-4">
  <label class="sr-only" for="Name">Name</label>
  <div class="input-group mb-2 mr-sm-2">
    <input type="text" class="form-control" formControlName="name" placeholder="name">
  </div>

  <label class="sr-only" for="Phone">Phone</label>
  <div class="input-group mb-2 mr-sm-2">
    <input type="text" class="form-control" formControlName="phone" placeholder="Phone">
  </div>

  <label class="sr-only" for="Address">Address</label>
  <div class="input-group mb-2 mr-sm-2">
    <input type="text" class="form-control" formControlName="address" placeholder="Address">
  </div>

  <label class="sr-only" for="membership">Membership</label>
  <div class="input-group mb-2 mr-sm-2">
    <select formControlName="membership" class="form-control">
      <option>Basic</option>
      <option>Pro</option>
      <option>Platinum</option>
    </select>
  </div>
  <button type="submit" class="btn btn-primary mb-2">Add Customer</button>
</form>

customer-list.component.html:

// customers/customer-list.component.ts
<h3>Customers</h3>
<table class="table table-hover">
  <thead>
    <tr class="table-primary">
      <th scope="col">Name</th>
      <th scope="col">Phone</th>
      <th scope="col">Address</th>
      <th scope="col">Membership</th>
      <th></th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <th scope="row">-</th>
      <td>-</td>
      <td>-</td>
      <td>-</td>
      <th>
        <a>edit</a>
        <br>
        <a>delete</a>
      </th>
    </tr>
  </tbody>
</table>

customer-edit.component.html:

// customers/customer-edit.component.ts
<div class="mt-4">
  <h3>Edit Customer</h3>
  <form class="form-inline mb-4">
 
    <label class="sr-only" for="Name">Name</label>
    <div class="input-group mb-2 mr-sm-2">
      <input type="text" class="form-control" formControlName="name" placeholder="name">
    </div>

    <label class="sr-only" for="Phone">Phone</label>
    <div class="input-group mb-2 mr-sm-2">
      <input type="text" class="form-control" formControlName="phone" placeholder="Phone">
    </div>

    <label class="sr-only" for="Address">Address</label>
    <div class="input-group mb-2 mr-sm-2">
      <input type="text" class="form-control" formControlName="address" placeholder="Address">
    </div>

    <label class="sr-only" for="membership">Membership</label>
    <div class="input-group mb-2 mr-sm-2">
      <select formControlName="membership" class="form-control">
        <option>Basic</option>
        <option>Pro</option>
        <option>Platinum</option>
      </select>
    </div>

    <button type="submit" class="btn btn-primary mb-2">Update Customer</button>

  </form>
</div>

And the last thing we’re going to do is create the customer model and the service so we have them ready.

Now go ahead and create a file called customer.model.ts and paste the following interface:

// customers/customer.model.ts
export interface Customer {
  id?: number;
  name: string;
  phone: string;
  address: string;
  membership: string;
}

Now, create the service with the command:

$ ng g s customers/customer

And add the following code inside:

// customers/customer.service.ts
import { Injectable } from "@angular/core";
import { HttpClient } from "@angular/common/http";
import { Observable } from "rxjs";
import { Customer } from "./customer.model";

@Injectable({
  providedIn: "root"
})
export class CustomerService {
  private customersUrl = "http://localhost:3000/customers";

  constructor(private http: HttpClient) {}

  getCustomers(): Observable<Customer[]> {
    return this.http.get<Customer[]>(this.customersUrl);
  }

  getCustomerById(payload: number): Observable<Customer> {
    return this.http.get<Customer>(`${this.customersUrl}/${payload}`);
  }

  createCustomer(payload: Customer): Observable<Customer> {
    return this.http.post<Customer>(this.customersUrl, payload);
  }

  updateCustomer(customer: Customer): Observable<Customer> {
    return this.http.patch<Customer>(
      `${this.customersUrl}/${customer.id}`,
      customer
    );
  }

  deleteCustomer(payload: number) {
    return this.http.delete(`${this.customersUrl}/${payload}`);
  }
}

This is a standard Angular service to communicate with the API. As you can see it allows us to read, create, update and delete customers from the server. This will create side effects in our application that we’ll handle with NgRx/effects. We can do that later.

For now, we have everything ready to implement the store and start working in our components. We’ll do that in the next video, where we’ll install the NgRx libraries and set up the store.