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 3: Beginning Frontend Development with Angular CLI


Activity 6: Designing the Frontend and Components for the Blogging Application

  1. Create a new Angular project named blog by pointing your CLI to the Blogging Application directory, and create an Angular CLI application with the name blog using the following code:

    ng new blog  
  2. Import the bootstrap theme and its resources from http://bit.ly/2DI7UsR by opening the link, and download the bootstrap theme and resources into the blog/src/assets folder.

  3. Update index.html with the necessary resource links using the following code:

    <!doctype html>
    <html lang="en">
    <head>
      <meta charset="utf-8">
      <title>Blog</title>
      <base href="/">
      <meta name="viewport" content="width=device-width, initial-scale=1">
    //[…]
    <script type="text/javascript" src="assets/js/main.js"></script>
    </body>
    </html>
File name: index.html
File name: header.component.html
File name: blog-home.component.html
File name: footer.component.html
File Name: view-post.component.html
  1. Create the header components and update the HTML template with the theme's header using the following code:

    ng generate component header
    <nav class="navbar navbar-expand-lg navbar-dark absolute_header">
      <div class="container">
        <a class="navbar-brand" href="#">
          <img class="etcodes-normal-logo" src="assets/images/logo-light.png" width="84" height="22" alt="Logo">
          <img class="etcodes-mobile-logo" src="assets/images/logo.png" width="84" height="22" alt="Logo">
        </a>
        <button class="navbar-toggler hamburger-menu-btn" type="button" data-toggle="collapse" data-target="#navbarNavDropdown" aria-controls="navbarNavDropdown"
    //[…]
                  </ul>
                </li>
              </ul>
            </li>
          </ul>
        </div>
      </div>
    </nav>
  2. Create the title-header component using the following code:

    <div class="bg-img-71 py-100px py-md-200px mb-80px">
      <div class="container">
          <div class="row">
              <div class="col-lg-6 offset-lg-3 text-center all-text-content-white">
                  <h1>MEAN Stack Courseware Blog Application Project</h1>
                  <p>Aenean lacinia bibendum sed consectetur. Etiam porta sem malesuada magna mollis euismod. Fusce
                      dapibus pertinax vix, varius cursus turpis dign issim id aliquam habemus tractatos.</p>
              </div>
          </div>
      </div>
    </div>
  3. Create the blog-home components and update the HTML template with the theme's content:

    ng generate component blog-home
                <!-- Blogs -->
    <title-header></title-header>
                <div class="container">
                    <div class="row">
                        <div class="col-lg-12">
                            <div class="row blog_posts stander_blog">
                                <div class="col-md-6 col-lg-4">
                                    <article>
                                        <div class="post_img card-blog-img">
                                            <img src="assets/images/home-27/2.jpg" alt="Card image cap">
                                            <a href="blog-standard-two-col-right-sidebar.html">
                                                <span class="card-blog-meta"> 
    //[…]
                            </div>
                        </div>
                    </div>
                </div>
  4. Create the footer components and update the HTML template with the theme's footer:

    ng generate component footer
    <footer class="web-footer footer bg-color-blackflame all-text-content-white">
        <div class="footer-widgets pt-85px pb-55px">
            <div class="container">
                <div class="row large-gutters">
                    <div class="col-lg-5 mb-30px">
                        <div class="footer-widget">
                            <h3>Paulappz</h3>
                            <p class="pt-20px pt-lg-155px">© 2018 Paulappz Themes</p>
    //[…]
                    </div>
                </div>
            </div>
        </div>
    </footer>
  5. Create the view-post components and update the HTML template:

    ng generate component view-post
      <div class="page-container scene-main scene-main--fade_In">
                <!-- view post -->
                <div class="container">
                    <div class="row">
                        <div class="col-md-12">
                            <div class="post_img">
                                <img src="assets/images/b3.jpg" alt="Card image cap">
    //[…]
                            </div>
                        </div>
                    </div>
                </div>
               
            </div>
  6. Update the root component template with the following code:

    <div id="main-content" class="bg-color-gray">
      <app-header></app-header>
      <div class="page-container scene-main scene-main--fade_In">
        <app-blog-home></app-blog-home>
        <app-footer></app-footer>
      </div>
    </div>
  7. Run ng serve -o to start the application. You will obtain the following output in the browser:

    Figure 3.16: Blog application theme update

    Figure 3.17: Blog application theme update

  8. Update the root component template with the following code:

    <div id="main-content" class="bg-color-gray">
      <app-header></app-header>
      <div class="page-container scene-main scene-main--fade_In">
        <view-post></view-post>
        <app-footer></app-footer>
      </div>
    </div>

    You will obtain the following output in the browser:

Activity 7: Writing Services and Making HTTP Request Calls to an API

File name: blog-home.component.html
File name: view-post.component.ts
  1. Create a service file for blog post articles by running the following command:

    ng generate service service/article
  2. Update app.module.ts file by importing the provider for ArticleService using the following code:

    import { BrowserModule } from '@angular/platform-browser';
    import { NgModule } from '@angular/core';
    import { AppComponent } from './app.component';
    import { BlogHomeComponent } from './blog-home/blog-home.component';
    import { HeaderComponent } from './header/header.component';
    import { FooterComponent } from './footer/footer.component';
    import { ArticleService } from './service/article.service';
    import { HttpClientModule } from '@angular/common/http';
    import { ViewPostComponent } from './view-post/view-post.component';
    import { TitleHeaderComponent } from './title-header/title-header.component';
    
    @NgModule({
      declarations: [
        AppComponent,
        BlogHomeComponent,
        HeaderComponent,
        FooterComponent,
        ViewPostComponent,
        TitleHeaderComponent
      ],
      imports: [
        BrowserModule,
        HttpClientModule
      ],
      providers: [ArticleService],
      bootstrap: [AppComponent]
    })
    export class AppModule { }
  3. Write the interface class in a newly created posts.ts file using the following code:

    export interface Post {
        photo: string;
        title: string;
        body: string;
        tag: string;
      }
  4. Import the Injectable, HttpClient, Post, and Observable modules using the following code:

    import { Injectable } from '@angular/core';
    import { HttpClient, HttpHeaders } from '@angular/common/http';
    import { Post } from '../posts'
    import { Observable } from 'rxjs';
  5. Declare Url variables and assign string values in the ArticleService class as shown:

    articlesUrl = 'http://localhost:3000/articles';
    articleUrl = 'http://localhost:3000/article/';
    article: any;
    httpOptions:any;
  6. Inject HttpClient and set HttpHeaders using the following code:

    constructor(private http: HttpClient) { 
        this.httpOptions = new HttpHeaders({ 
          'Access-Control-Allow-Origin':'*',
          'Access-Control-Allow-Methods':'PUT, POST, GET, DELETE, OPTIONS',
         });
      }
  7. Write the CRUD service functions:

      getArticles(): Observable<Post> {
        this.article = this.http.get<Post>(this.articlesUrl);
        return this.article;
      }
      getArticle(id: number) {
        return this.http.get(this.articleUrl + id);
      }
    
      /** POST: add a new article to the database */
      PostArticle(article: Post): Observable<Post> {
      
        return this.http.post<Post>(this.articlesUrl,
          { 'title': article.title, 'body': article.body, 'tag': article.tag, 'photo': article.photo }, {
            headers: this.httpOptions
          })
      }
    
      deleteArticle(id: number):
        Observable<{}> {
        return this.http.delete(this.articleUrl + id, {
          headers: this.httpOptions
        })
      }
    
      updateArticle(id: number, article: Post): Observable<Post> {
        return this.http.put<Post>(this.articleUrl + id, { 'title': article.title, 'body': article.body, 'tag': article.tag, 'photo': article.photo },{
          headers: this.httpOptions
        })
      }
    }
  8. Update the blog-home components class file with the following code:

    import { Component, OnInit } from '@angular/core';
    // Import service
    import { ArticleService } from '../service/article.service';
    @Component({
      selector: 'app-blog-home',
      templateUrl: './blog-home.component.html',
      styleUrls: ['./blog-home.component.css']
    })
    export class BlogHomeComponent implements OnInit {
      articles:any=[];
    //Inject service
      constructor(private articleService:ArticleService) { }
      ngOnInit() {
     this.articleService.getArticles()
    .subscribe(
      res => {
        for(let key in res){
          this.articles.push(res[key]);
        }
      },
      err => {
        console.log("Error occured");
      }
    );
     }
     }
  9. Update the blog-home components template file with the following code:

    <app-title-header></app-title-header>
        <div class="container">
            <div class="row">
                <div class="col-lg-12">
                    <div  class="row blog_posts stander_blog">
                        <div class="col-md-6 col-lg-4"   *ngFor="let article of //[…]
                        
                    </div>
                </div>
            </div>
        </div>
  10. Update the root component template with the following code:

    <div id="main-content" class="bg-color-gray">
      <app-header></app-header>
      <div class="page-container scene-main scene-main--fade_In">
        <app-blog-home></app-blog-home>
        <app-footer></app-footer>
      </div>
    </div>
  11. Run ng serve -o on the command line to view the following output:

    Figure 3.18: Blog-home page of the application

  12. Update the view-post components class file with the following code:

    import { Component, OnInit } from '@angular/core';
    import { ArticleService } from '../service/article.service';
    @Component({
      selector: 'view-post',
      templateUrl: './view-post.component.html',
      styleUrls: ['./view-post.component.css']
    })
    export class ViewPostComponent implements OnInit {
      id: any;
      article: any;
      constructor( private articleService: ArticleService) { }
      ngOnInit() {
          this.id = '5b9426b70e473447f400eeb9' // id of first post from API
          this.articleService.getArticle(this.id)
            .subscribe(
              res => {
                console.log(res)
                this.article = res;
              },
              err => {
                console.log("Error occured");
              }
            );
      }
    }
  13. Update the view-post components template file with the following code:

    <div class="page-container scene-main scene-main--fade_In">
                <!-- Blog post -->
                <div class="container"> 
                    <div class="row">
                        <div class="col-md-12">
                            <div class="post_img">
                                <img src="https://{{article.photo}}" alt="Card image cap">
    //[…]
                            </div>
                        </div>
                    </div>
                </div> 
               
            </div>
  14. Update the root component template with the following code:

    <div id="main-content" class="bg-color-gray">
      <app-header></app-header>
      <div class="page-container scene-main scene-main--fade_In">
        <view-post></view-post>
        <app-footer></app-footer>
      </div>
    </div>
  15. Run ng serve -o to start the application. You should obtain the following output:

    Figure 3.19: View-post page of the application

Activity 8: Creating a Form Application Using the Reactive/Model-Driven Method

File name: packt-student-reactive-form.component.html
  1. Create an Angular CLI application named Reactive form:

    ng new reactive-form
  2. Create a component and name it PacktStudentReactiveForm:

    ng generate component reactive-form/ PacktStudentReactiveForm
  3. Register the reactive forms module in app.module.ts and add it to import properties to activate the reactive form using the following code:

    import { ReactiveFormsModule } from '@angular/forms';
    import { FormsModule } from '@angular/forms';
    
    imports: [
        BrowserModule,
        FormsModule, 
        ReactiveFormsModule
      ],
  4. Import the FormControl and FormGroup modules into the reactive form component (packt-student-reactive-form.component.ts):

    import { FormGroup, FormControl, Validators, FormBuilder } from '@angular/forms';
    import { Component, OnInit } from '@angular/core';
  5. Declare and initialize the array in the reactive components class, as follows:

      courseTitles = ['MEAN Stack', 'MEVN Stack', 'MERN Stack'];
  6. Create FormGroup and FormControl variable instances:

    myform : FormGroup;
    name : FormControl;
    courseTitle : FormControl;
    duration : FormControl;
    constructor() { }
  7. Create functions to initialize and validate using the following code:

    ngOnInit() {
      this.createFormControls();
      this.createForm();
    }
    createFormControls() { 
      this.name = new FormControl('Paul Adams', Validators.required),
      this.courseTitle = new FormControl(this.courseTitles[0], Validators.required),
      this.duration = new FormControl('6 days')
    }
    createForm() { 
      this.myform = new FormGroup({
        name: this.name,
        courseTitle : this.courseTitle,
        duration: this.duration
      });
    }
    
    submitted = false;
    
    onSubmit() { this.submitted = true; console.log(this.name) }
    newStudent() {
      this.myform.reset();
    }
  8. Register the control and form group in the html form template of the reactive component (packt-student-reactive-form.component.html) using the following code:

    <div class="container">
        <div *ngIf="!submitted">
            <h1>Packt Course Form</h1>
    //[…]
          </select>
                    <div *ngIf="courseTitle.invalid" class="alert alert-danger">
                        courseTitle is required
                    </div>
                </div>
                <div class="form-group">
                    <label for="duration">Course Duration</label>
                    <input type="text" class="form-control" id="duration" formControlName="duration">
                </div>
                <button type="submit" class="btn btn-success" [disabled]="">Submit</button>
                <button type="button" class="btn btn-default" (click)="newStudent();">New Student</button>
            </form>
    </div>
  9. Add a submitted view to the template:

        <div *ngIf="submitted">
            <h2>You submitted the following:</h2>
            <div class="row">
                <div class="col-xs-3">Name</div>
                <div class="col-xs-9  pull-left">{{name.value}}</div>
            </div>
            <div class="row">
                <div class="col-xs-3">Course Duration</div>
                <div class="col-xs-9 pull-left">{{duration.value}}</div>
            </div>
            <div class="row">
                <div class="col-xs-3">Packt Course Title</div>
                <div class="col-xs-9 pull-left">{{courseTitle.value}}</div>
            </div>
            <br>
            <button class="btn btn-primary" (click)="submitted=false">Edit</button>
        </div>
    </div>
  10. Update the components style sheet (packt-student-reactive-form.component.css) and the main application style sheet (style.css) using the following code:

    // packt-student-reactive-form.component.css
    .ng-valid[required],
    .ng-valid.required,
    .has-success {
        /* border-left: 5px solid #42A948; */
        /* green */
    }
    
    .ng-invalid:not(form) {
        /* border: 1px solid #a94442; */
        /* red */
    }
    
    // style.css
    /* You can add global styles to this file, and also import other style files */
    @import url('https://unpkg.com/[email protected]/dist/css/bootstrap.min.css');
  11. Update the root template file (app.componets.html file) by hosting the form component src/app/app.component.html using the following code:

    src/app/app.component.html
    < app-packt-student-reactive-form ></ app-packt-student-reactive-form >
  12. Launch the application by running the following snippet in the command-line terminal and go to the address localhost:4200:

    ng serve --open

    You will obtain the following output:

    Figure 3.20: Reactive/model-driven form

Activity 9: Creating and Validating Different Forms Using the Template and Reactive-Driven Method

File name: login.component.html

Update the app component template with the following snippet and run ng serve to view the User Login form output:

File name: register.component.html
File name: create.component.html
  1. Create the User Login form component using the following code:

    ng generate component login
  2. Update the User Login form component class and update the HTML template to be reactive/model-driven using the following code:

    import { Component, OnInit } from '@angular/core';
    import { FormGroup, FormControl, Validators, FormBuilder } from '@angular/forms';
    @Component({
      selector: 'login',
      templateUrl: './login.component.html',
      styleUrls: ['./login.component.css']
    })
    export class LoginComponent {
      loginForm: FormGroup;
      displayMessage: string;
      submitted = false;
      constructor(private formBuilder: FormBuilder) {
        /* Declare Reactive Form Group here */
        this.loginForm = this.formBuilder.group({
          email: ['', [
            Validators.required,
            Validators.pattern("[^ @]*@[^ @]*")
          ]],
          password: ['', [
            Validators.minLength(8),
            Validators.required
          ]],
        });
    
      }
    
      submitForm() {
        this.submitted = true;
        /* Change the display message on button click / submit form */
        if (this.loginForm.valid) {
           this.loginUser();
        }
    
      }
    
       loginUser() {
      console.log('Logged In sucessfully')
      }
    }

    The template is updated with the following:

    <title-header></title-header>
    <div class="" style="padding-bottom: 3rem!important;">
      <div class="row">
        <div class="col-md-6 mx-auto">
          <!-- form card login -->
          <div class="card rounded-0">
    //[…]
          <!-- /form card login -->
        </div>
      </div>
    </div>
    <div id="main-content" class="bg-color-gray">
      <app-header></app-header>
      <div class="page-container scene-main scene-main--fade_In">
        <app-login></app-login>
        <app-footer></app-footer>
      </div>
    </div>

    You will obtain the following output once you type http://localhost:4200/login in the browser:

    Figure 3.21: Reactive login form

  3. Create the User Registration form component:

    ng generate component register
  4. Create an exportable user class file in the app directory using the following code:

    export class Users {
        constructor(
        public fullName: string,
        public email: string,
        public password: string
    ) {  }
    }
  5. Update the User Registration form component class and update the HTML template to be template-driven.

    The class is updated as follows:

    import { Component, OnInit } from '@angular/core';
    import { Users } from '../users';
    
    @Component({
      selector: 'app-register',
      templateUrl: './register.component.html',
      styleUrls: ['./register.component.css']
    })
    export class RegisterComponent implements OnInit {
      model = new Users('', '', '');
      constructor(/*private auth: AuthService,
        private router: Router*/) { }
      ngOnInit() {
      }
      onSubmit() {
         this.registerUser();
      }
      registerUser() {
    console.log('Registration Successful')
       }

    The template is updated as follows:

    <title-header></title-header>
    <div>
      <div class="row">
        <div class="col-md-6 mx-auto">
          <!-- form card login -->
          <div class="card rounded-0">
              <h3 class="mb-0" style="text-align:center">Register  Admin User</h3>
            <div class="card-header">
            </div>
            <div class="card-body">
              <form (ngSubmit)="userForm.form.valid && onSubmit()" 
    //[…]
          <!-- /form card login -->
        </div>
      </div>
    </div>
  6. Update the app component template with the following snippet and run ng serve to view the User Registration form output:

    <div id="main-content" class="bg-color-gray">
      <app-header></app-header>
      <div class="page-container scene-main scene-main--fade_In">
        <app-register></app-register>
        <app-footer></app-footer>
      </div>
    </div>

    You will obtain the following output once you run http://localhost:4200/register in the browser:

    Figure 3.22: Template-driven Register form

  7. Create the Post Create/Edit form component and an exportable Posts class:

    ng generate component create
    export class Posts {
        constructor(
        public title: string,
        public body: string,
        public tag: string,
        public photo: string,
    ) {  }
    }
  8. Update the Post Create/Edit form component class and update the HTML template to be template-driven.

    The class is updated as follows:

    import { Component, OnInit } from '@angular/core';
    import { Posts } from '../post';
    @Component({
      selector: 'app-create',
      templateUrl: './create.component.html',
      styleUrls: ['./create.component.css']
    })
    export class CreateComponent implements OnInit {
      tags = ['POLITICS', 'ECONOMY', 'EDUCATION','STORY','TECH'];
      model = new Posts('','','','');
      submitted = false;
      constructor() { }
      onSubmit() { 
        this.submitted = true; 
      console.log(this.model)
    }
      ngOnInit() {
      }
    }

    The template is updated as follows:

    <title-header></title-header>
    <div class="py-5">
      <div class="row">
        <div class="col-md-6 mx-auto">
          <!-- form card login -->
          <div class="card rounded-0">
              <h3 style="text-align:center" class="mb-0">Create Post</h3>
              <div class="card-header">
                </div>
            <div class="card-body">
              <form (ngSubmit)="postForm.form.valid && onSubmit()" 
    //[…]
                <button type="submit" class="btn btn-success">Submit</button>
              </form>
            </div>
            <!--/card-block-->
          </div>
          <!-- /form card login -->
        </div>
      </div>
    </div>
  9. Update the app component template with the following snippet and run ng serve to view the Post Create/Edit form output:

    <div id="main-content" class="bg-color-gray">
      <app-header></app-header>
      <div class="page-container scene-main scene-main--fade_In">
        <app-create></app-create>
        <app-footer></app-footer>
      </div>
    </div>

    You will obtain the following output once you type http://localhost:4200/create in the browser window:

    Figure 3.23: Template-driven post create/edit form

Activity 10: Implementing a Router for the Blogging Application

File name: blog-home.component.html
  1. Import RouterModule into the app module file (app.module.ts) and update the import property:

    import { RouterModule, Routes } from '@angular/router';
    
    imports: [
        BrowserModule,
        HttpClientModule,
        RouterModule.forRoot(appRoutes),
        FormsModule,
        ReactiveFormsModule,
        BrowserAnimationsModule
      ],
  2. Configure the route in app.module.ts as follows:

    const appRoutes: Routes = [
      { path: 'blog', component: BlogHomeComponent,
        data: { title: 'Article List' }},
      { path: 'blog/post/:id',      component: ViewPostComponent },
      { path: 'login', component: LoginComponent},
      { path: 'register', component: RegisterComponent},
      { path: 'create', component: CreateComponent},
    
      { path: '',
        redirectTo: '/blog',
        pathMatch: 'full'
      },
      // { path: '**', component: PageNotFoundComponent }
    ];
  3. Add router-outlet to the app.component.html file:

    <div id="main-content" class="bg-color-gray">
      <app-header></app-header>
      <div class="page-container scene-main scene-main--fade_In">
        
        <router-outlet></router-outlet>
    
        <app-footer></app-footer>
      </div>
    </div>
  4. Add the router link to the blog-home component:

    <title-header></title-header>
        <div class="container">
            <div class="row">
                <div class="col-lg-12">
                    <div  class="row blog_posts stander_blog">
                        <div class="col-md-6 col-lg-4"   *ngFor="let article of articles">
                            <article>
                                    <a routerLink="post/{{article._id}}">
                                <div class="post_img card-blog-img">
                                    <img src="https://{{article.photo}}" 
    //[…]
                        
                    </div>
                </div>
            </div>
    
        </div>
  5. Start the server and serve the Angular application using the CLI with the following commands:

    > node server.js
    > ng serve -o
  6. Open the browser and input http://localhost:4200/blogin in the URL address bar to view the router in action.

    You will obtain the following output:

    Figure 3.24: Blog post route

    If you click on one of the posts, it will navigate to the view-post page, as shown:

    Figure 3.25: Route to view-post page