Book Image

MongoDB, Express, Angular, and Node.js Fundamentals

By : Paul Oluyege
Book Image

MongoDB, Express, Angular, and Node.js Fundamentals

By: Paul Oluyege

Overview of this book

MongoDB, Express, Angular and Node.js Fundamentals is a practical guide to the tried-and-true production-ready MEAN stack, with tips and best practices. The book begins by demystifying the MEAN architecture. You’ll take a look at the features of the JavaScript libraries, technologies, and frameworks that make up a MEAN stack. With this book, you'll not only learn how to develop highly scalable, asynchronous, and event-driven APIs quickly with Express and Node.js, but you'll also be able put your full-stack skills to use by building two full-fledged MEAN applications from scratch. You’ll understand how to build a blogging application using the MEAN stack and get to grips with user authentication using MEAN. As you progress through the chapters, you’ll explore some old and new features of Angular, such as pipes, reactive forms, modules and optimizing apps, animations and unit testing, and much more. By the end of the book, you’ll get ready to take control of the MEAN stack and transform into a full-stack JavaScript developer, developing efficient web applications using Javascript technologies.
Table of Contents (9 chapters)
MongoDB, Express, Angular, and Node.js Fundamentals
Preface

Chapter 5: Angular Declarables, Bootstrapping, and Modularity


Activity 13: Communicating Between Two Components Using Observable

  1. Create the app-header component using the CLI, as shown here:

    ng generate component app-header
  2. Create the app-content component using the following CLI command:

    ng generate component app-content
  3. Create the user model and interface in user.model.ts using the following command:

    export interface User {
      firstName: string;
      lastName: string;
    }
  4. Create the user service and update the server:

    ng generate server user
    import { Injectable } from '@angular/core';
    import { BehaviorSubject } from 'rxjs';
    
    @Injectable()
    export class UserService {
      private user = new BehaviorSubject<boolean>(false); //create user as behavior
      cast = this.user.asObservable(); //cast user as observable
    
      constructor() { }
    
      User(newUser) {
        this.user.next(newUser);
      }
    }
  5. Define the user and inject service into the app-header.component.ts class using the following code:

    import { Component, OnInit } from '@angular/core';
    import { User } from '../user/user.model';
    import { UserService } from '../user.service';
    
    @Component({
      selector: 'app-header',
      templateUrl: './app-header.component.html',
      styleUrls: ['./app-header.component.scss']
    })
    export class AppHeaderComponent implements OnInit {
      user: User = {
        firstName: 'Paul',
        lastName: 'Oluyege'
      };
      isLoggedIn: boolean;
      constructor(private usersService:UserService) { }
  6. Define the user and inject service into the app-content.component.ts class using the following code:

    import { Component, OnInit } from '@angular/core';
    import { User } from './../user/user.model';
    import { UserService } from '../user.service';
    
    @Component({
      selector: 'app-content',
      templateUrl: './app-content.component.html',
      styleUrls: ['./app-content.component.scss']
    })
    export class AppContentComponent implements OnInit {
      user: User = {
        firstName: 'Paul',
        lastName: 'Oluyege'
      };
      isLoggedIn: boolean;
      constructor(private usersService: UserService) { }
  7. Write ngOnInit(), login(), signup(), and logout() methods for the app-header.component.ts class, as shown here:

    ngOnInit() {
        this.usersService.cast.subscribe(user=> this.isLoggedIn = user);
      }
    
      login() {
        this.isLoggedIn = true;
        this.usersService.User(this.isLoggedIn);
      }
    
      signup() {
        this.isLoggedIn = true;
        this.usersService.User(this.isLoggedIn);
      }
    
      logout() {
        this.isLoggedIn = false;
        this.usersService.User(this.isLoggedIn);
      }
    
    }
  8. Write ngOnInit(), login(), signup(), and logout() methods for the app-content.component.ts class, as shown here:

    ngOnInit() {
        this.usersService.cast.subscribe(user => this.isLoggedIn = user);
        this.isLoggedIn = false;
      }
    
      login() {
        this.isLoggedIn = true;
        this.usersService.User(this.isLoggedIn);
      }
    
      logout() {
        this.isLoggedIn = false;
        this.usersService.User(this.isLoggedIn);
      }
    }
  9. Update the app-header.component.html template using the following code:

    <div class="app-header">
      <div class="title" routerLink="/">Packt MEANStack Courseware</div>
      <div class="profile-dropdown" *ngIf="isLoggedIn">
        <div class="initials">
          {{user.firstName.charAt(0)}}{{user.lastName.charAt(0)}}
        </div>
      </div>
      <div class="action-btns" *ngIf="!isLoggedIn">
        <button class="app-btn login-btn" (click)="login()">Login</button>
        <button class="app-btn signup-btn" (click)="signup()">Signup</button>
      </div>
      <div class="action-btns" *ngIf="isLoggedIn">
        <button class="app-btn logout-btn" (click)="logout()">Logout</button>
      </div>
    </div>
  10. Update the app-content.component.html template using the following code:

    <div class="app-content">
      <div class="user-profile" *ngIf="isLoggedIn">
        Hi {{user.firstName}} {{user.lastName}}! Welcome to MEANStack class
      </div>
      <div class="action-btn">
        <button class="app-btn" *ngIf="!isLoggedIn" (click)="login()">Login</button>
        <button class="app-btn" *ngIf="isLoggedIn" (click)="logout()">Logout</button>
      </div>
    </div>
  11. Update styles for both components (app-header and app-content), as shown here:

    // app-content-component.scss
    .app-content {
        padding: 40px;
      
        .user-profile {
          margin-bottom: 20px;
        }
      }  
    // app-header-component.scss
    .app-header {
        background: #e94e06;
        height: 44px;
        color: white;
        padding: 6px 10px;
        display: flex;
        flex-direction: row;
        align-items: center;
        box-shadow: 0 3px 5px -1px rgba(0,0,0,.2), 0 6px 10px 0 rgba(0,0,0,.14), 0 1px 18px 0 rgba(0,0,0,.12);
        .logo {
    //[…]
            }
          }
        }
      }
  12. Update the app.component.html template with the following code:

    <app-header></app-header>
    <app-content></app-content>
  13. Run ng serve on the CLI and open the browser on localhost:4200 to see the output and test it, as shown in the following screenshot:

    Figure 5.10: Synchronization of two components

Activity 14: Creating a Lazy Loaded Application

  1. Create an Angular project with the name users, as shown here:

    ng new users --routing

    Note that the --routing flag generates a file called app-routing.module.ts, which is one of the files you need for setting up lazy loading for your feature module.

  2. Create a users-list feature module with routing:

    ng generate module users-list  --routing
  3. Add a user-list component to the feature module using the following code:

    ng generate component users-list / users-list
  4. Create a users-details feature module with routing using the following code:

    ng generate module users-details  --routing
  5. Add a user-detail component to the feature module using the following code:

    ng generate component users-detail / users-detail	
  6. Globally install the json-server on your system using npm or yam:

    npm install -g json-server
  7. Create a new JSON file named db.json and fill it with data from https://api.myjson.com/bins/10v4ns. Then, launch this file on the json-server using the following code:

    json-server --watch db.json
  8. Add a user-list service using the following code:

    ng generate service service/users-list
  9. Update the routes array in AppRoutingModule with the following code:

    import { NgModule } from '@angular/core';
    import { Routes, RouterModule } from '@angular/router';
    
    const routes: Routes = [
      {
        path: 'userslist',
        loadChildren: './users-list/users-list.module#UsersListModule'
      },
      {
        path: 'userslist/:id',
        loadChildren: './users-detail/users-detail.module#UsersDetailModule'
      },
    
      {
        path: '',
        redirectTo: '',
        pathMatch: 'full'
        
      }
    ];
    
    @NgModule({
      imports: [RouterModule.forRoot(routes)],
      exports: [RouterModule]
    })
    export class AppRoutingModule { }
  10. Configure the feature module's routes in users-list-routing.module.ts by first importing the component at the top of the file with the other JavaScript import statements and then add the route to UserListComponent:

    Here is the code for importing the component:

    import { NgModule } from '@angular/core';
    import { Routes, RouterModule } from '@angular/router';
    import {  UsersListComponent} from './users-list.component'
    
    const routes: Routes = [
        { path: "", component: UsersListComponent},
    ];
    
    
    @NgModule({
      imports: [RouterModule.forChild(routes)],
      exports: [RouterModule]
    })
    export class UsersListRoutingModule { }
  11. Configure the feature modules for users-detail-routing.module.ts using the following code:

    import { NgModule } from '@angular/core';
    import { Routes, RouterModule } from '@angular/router';
    import {  UsersDetailComponent} from './users-detail.component'
    
    const routes: Routes = [
        { path: "", component: UsersDetailComponent},
    ];
    
    @NgModule({
      imports: [RouterModule.forChild(routes)],
      exports: [RouterModule]
    })
    export class UsersDetailRoutingModule { }
  12. Create the user model and update it with the following code:

    ng generate cl model/user
    export class Users {
      first: string;
      second: string;
      id: number;
      phone:string;
      picture:string;
      email:string;
     }
  13. Write the service functions, as shown here:

    import { Injectable } from '@angular/core';
    import { Users } from "../model/users.model";
    import {HttpClient} from '@angular/common/http';
    import { Observable } from 'rxjs';
    
    @Injectable()
    export class UsersListService {
      dataurl = "http://localhost:3000/results";
      constructor(private http: HttpClient) { }
    
      
      public getUsers(): Observable<Users[]> {
        return this.http.get<Users[]>(this.dataurl);
      }
    
      public getUser(id: string): Observable<Users> {
        return this.http.get<Users>('${this.dataurl}?id=${id}');
      }
    
    }
  14. Update and inject the service into users-list.component.ts using the following code:

    import { Component, OnInit, OnDestroy } from '@angular/core';
    import { Router } from '@angular/router';
    import { Users } from "../model/users.model";
    import { UsersListService } from "../service/users-list.service";
    @Component({
      selector: 'app-users-list',
      templateUrl: './users-list.component.html',
      styleUrls: ['./users-list.component.css']
    })
    export class UsersListComponent implements OnInit {
      userlists: Users[];
      constructor(private router: Router, private usersService: UsersListService) { }
    
      ngOnInit() {
        this.usersService.getUsers().subscribe((user: any) => {
          this.userlists = user;
          console.log(this.userlists);
        });
      }
    
    
    }
  15. Update and inject service into users-details.component.ts, as shown here:

    import { Component, OnInit } from '@angular/core';
    import { ActivatedRoute } from "@angular/router";
    import { Router } from '@angular/router';
    import { Users } from "../model/users.model";
    import { UsersListService } from "../service/users-list.service";
    
    @Component({
      selector: 'app-users-detail',
      templateUrl: './users-detail.component.html',
      styleUrls: ['./users-detail.component.css']
    })
    export class UsersDetailComponent implements OnInit {
      user: Users;
      constructor(private router: Router, private route: ActivatedRoute, private usersService: UsersListService) { }
    
      ngOnInit(): void {
    
        this.usersService.getUser(this.route.snapshot.params["id"]).subscribe((user: any) => {
          this.user = user;
        });
    
    
      }
  16. Style the user-list component using the following code:

    .selected {
        background-color: #CFD8DC !important;
        color: white;
      }
    //[…]
        .list-type1 ol.selected:hover {
          background-color: #BBD8DC !important;
          color: white;
        }
  17. Style the users-details components using the following code:

    @import url(https://fonts.googleapis.com/css?family=Raleway|Varela+Round|Coda);
    @import url(http://weloveiconfonts.com/api/?family=entypo);
    
    [class*="entypo-"]:before {
      font-family: 'entypo', sans-serif;
    }
    //[…]
    .previous {
        background-color: #f1f1f1;
        color: black;
    }
  18. Update the app.component.html template, as shown here:

    <router-outlet></router-outlet>
  19. Go to localhost:4200 and then test for /userslist and /userslist/1, as follows:

    Type localhost/4200/userslist on the browser address bar and observe the number of resources requested, as shown here:

    Figure 5.11: Output for the user list

  20. Type localhost/4200/userslist/1 on the browser address bar and observe the number of resources requested, as shown here:

    Figure 5.12: The resources that have been requested for a given user