Angular 8 – AppDividend https://appdividend.com Latest Code Tutorials Thu, 17 Oct 2019 02:39:37 +0000 en-US hourly 1 https://wordpress.org/?v=5.2.4 https://appdividend.com/wp-content/uploads/2017/08/cropped-ApDivi-32x32.png Angular 8 – AppDividend https://appdividend.com 32 32 Angular 8 Forms Tutorial | Angular Reactive and Template Forms Example https://appdividend.com/2019/06/07/angular-8-forms-tutorial-angular-reactive-and-template-forms-example/ https://appdividend.com/2019/06/07/angular-8-forms-tutorial-angular-reactive-and-template-forms-example/#respond Fri, 07 Jun 2019 16:47:56 +0000 http://localhost/wordpress/?p=8190 Angular 8 Forms Tutorial | Angular Reactive and Template Forms Example

Angular 8 Forms Tutorial | Angular Reactive and Template Forms Example is today’s topic. If you are new to Angular 8, then check out my Angular 8 Tutorial. If you do not know how to upgrade to Angular 8 via Angular CLI, then check out my Angular 8 Upgrade tutorial. Managing the user input with forms […]

The post Angular 8 Forms Tutorial | Angular Reactive and Template Forms Example appeared first on AppDividend.

]]>
Angular 8 Forms Tutorial | Angular Reactive and Template Forms Example

Angular 8 Forms Tutorial | Angular Reactive and Template Forms Example is today’s topic. If you are new to Angular 8, then check out my Angular 8 Tutorial. If you do not know how to upgrade to Angular 8 via Angular CLI, then check out my Angular 8 Upgrade tutorial. Managing the user input with forms is the cornerstone of many web applications.

Web app use forms to enable the users to log in, to update a profile, to enter sensitive information, and to perform many data-entry tasks.

Angular 8 Forms Tutorial

Angular provides two different approaches for managing the user input through the forms.

  1. Reactive approach
  2. Template-driven approach

Both reactive and template-driven forms share underlying common building blocks which are the following.

  1. FormControl: It tracks the value and validation status of the individual form control.

  2. FormGroup: It tracks the same values and status for the collection of form controls.
  3. FormArray:It tracks the same values and status for the array of the form controls.
  4. ControlValueAccessor: It creates the bridge between Angular FormControl instances and native DOM elements.

Reactive forms in Angular 8

Reactive forms or Model-driven forms are more robust, scalable, reusable, and testable. If forms are the key part of your application, or you’re already using reactive patterns for building your web application, use reactive forms.

In Reactive Forms, most of the work is done in the component class.

Template-driven forms in Angular 8

Template-driven forms are useful for adding the simple form to an app, such as the email list signup form. They’re easy to add to a web app, but they don’t scale as well as the reactive forms.

If you have the fundamental form requirements and logic that can be managed solely in the template, use template-driven forms.

In template-driven forms, most of the work is done in the template.

Example of Template-driven form in Angular 8

Okay, now let’s install the fresh Angular 8 application.

Then go to an app.module.ts file and add the following code.

// app.module.ts

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';

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

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule,
    FormsModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

In the above file, we have imported the FormsModule from the @angular/forms library.

Now, we can use the FormsModule inside our app.component.ts file.

// app.component.ts

import { Component, OnInit } from '@angular/core';
@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit {
   constructor() { }
   ngOnInit() {
   }
   onClickSubmit(formData) {
      alert('Your Email is : ' + formData.email);
   }
}

In this file, we have defined on onClickSubmit function, which will trigger when the user clicks the submit button on the form. The function also accepts one argument called formData, which is the object of the entire form values.

Through that formData object, we can access all the form field values. In our case, I only need the user’s email id. In the general scenario, we want to pass that object to the POST request to the backend server to store the user’s data.

Now, only remaining thing is to write the HTML of the app component. So, write the following code inside the app.component.html file.

<form #login = "ngForm" (ngSubmit) = "onClickSubmit(login.value)" >
  <input type = "text" name = "email" placeholder = "email" ngModel>
  <br/>
  <input type = "password" name = "pwd" placeholder = "password" ngModel>
  <br/>
  <input type = "submit" value = "submit">
</form>

We have created the web form with input tags having email, password and the submit button. We have assigned a type, name, and placeholder attributes to it.

In the template driven forms, we need to create a model form controls by adding the ngModel directive and the name attribute. Thus, whenever we want Angular to access our data from forms, add ngModel to that tag as shown above. Now, if we have to read an email and password, we need to add a ngModel across it.

If you close look at the form, we have also added the ngForm to the #login. The ngForm directive needs to be added to a form template that we have created.

Atlast, We have also added the function onClickSubmit and assigned login.value to it.

Save the file and start the angular development server by the following command.

ng serve -o

You will see the browser screen with the login form. Now fill the form and you will see something like the following image.

Angular 8 Forms Tutorial | Angular Forms Example

 

So, that is it for the Template-driven forms in Angular 8.

Model-driven or Reactive Forms in Angular 8

In the model-driven form, we need to import a ReactiveFormsModule from @angular/forms and use the same in the imports array.

There is a change which goes in app.module.ts. See the app.module.ts file.

// app.module.ts

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';

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

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule,
    FormsModule,
    ReactiveFormsModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

In the app.component.ts file, we need to import the few modules for the model-driven form. For example, import { FormGroup, FormBuilder } from ‘@angular/forms’.

See the following app.component.ts file.

// app.component.ts

import { Component, OnInit } from '@angular/core';
import { FormGroup, FormBuilder } from '@angular/forms';
@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit {
  angForm: FormGroup;
  constructor(private fb: FormBuilder) {
    this.createForm();
  }
  createForm() {
    this.angForm = this.fb.group({
      email: [''],
      password: ['']
    });
  }
  onClickSubmit(email, password) {
    alert('Your Email is : ' + email);
  }
   ngOnInit() {
   }
}

In the above code, we have used a FormBuilder to create a form and initialize the value of two fields which is empty.

We have also defined one function called onClickSubmit() which accepts the two parameter email and password.

So,  when the user pressed the submit button, we got the values here and then we send these values with the POST request to the backend server.

Finally, write the app.component.html file.

<form [formGroup]="angForm">
  <input type = "text" 
        name = "email" 
        placeholder = "email" 
        formControlName="email" 
        #email>
  <br/>
  <input type = "password" 
        name = "pwd" 
        placeholder = "password" 
        formControlName="password" 
        #password>
  <br/>
  <input type = "submit" 
          value = "submit" 
          (click) = "onClickSubmit(email.value, password.value)" >
</form>

Now, save the above file and go to the Angular app and you will see the same output as we have got in the template-driven approach.

One of the advantages of the Model-driven approach is that the Validations become very easy.

Finally, we have seen both the approaches and Angular 8 Forms Tutorial | Angular Reactive and Template Forms Example is over.

The post Angular 8 Forms Tutorial | Angular Reactive and Template Forms Example appeared first on AppDividend.

]]>
https://appdividend.com/2019/06/07/angular-8-forms-tutorial-angular-reactive-and-template-forms-example/feed/ 0
Angular 8 File Upload Example | Angular Image Upload https://appdividend.com/2019/06/07/angular-8-file-upload-tutorial-with-example-angular-image-upload/ https://appdividend.com/2019/06/07/angular-8-file-upload-tutorial-with-example-angular-image-upload/#comments Fri, 07 Jun 2019 10:11:55 +0000 http://localhost/wordpress/?p=8169 Angular 8 File Upload Tutorial With Example | Angular Image Upload

Angular 8 File Upload Example | Angular Image Upload Tutorial is today’s topic. If you are new to Angular 8, then check out my Angular 8 Tutorial. In this Angular Image Upload demo, we will use the ng2-file-upload library to upload a file to the node server. We use Node.js as a backend server. We […]

The post Angular 8 File Upload Example | Angular Image Upload appeared first on AppDividend.

]]>
Angular 8 File Upload Tutorial With Example | Angular Image Upload

Angular 8 File Upload Example | Angular Image Upload Tutorial is today’s topic. If you are new to Angular 8, then check out my Angular 8 Tutorial. In this Angular Image Upload demo, we will use the ng2-file-upload library to upload a file to the node server. We use Node.js as a backend server. We install Angular using Angular 8 CLI and then start working on this Angular File Upload demo. For handling the uploaded files at the backend server, we use the multer library.

Angular 8 File Upload Example

Now, set up the angular project using the following command.

ng new ng8fileupload

Angular 8 File Upload Tutorial

Now, spin up the angular app using the following command.

ng serve --open

#Install rxjs-compat library

So, to fill the gap between Angular 8 and third-party packages, we need to install the rxjs-compat library. That is it.

npm install rxjs-compat --save

Now, you will not get any error regarding any rxjs observables.

#Install Bootstrap 4

Go to your terminal and type the following command.

npm install bootstrap --save

Now, include that above file inside the angular.json file.

"styles": [
   "src/styles.css",
   "./node_modules/bootstrap/dist/css/bootstrap.min.css"
 ],

It will include the library in Angular application.

#Install an ng-file-upload library

Type the following command to install the library.

npm install ng2-file-upload --save

Now, write a following code inside an app.module.ts file.

// app.module.ts

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { FileSelectDirective } from 'ng2-file-upload';
import { FormsModule } from '@angular/forms';

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

@NgModule({
  declarations: [
    AppComponent,
    FileSelectDirective
  ],
  imports: [
    BrowserModule,
    FormsModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

We have imported the FileSelectDirective from ng2-file-upload.

Also, we need to import the FormsModule. We need FormsModule because we need to write the file upload component.

Now, write the following code inside an app.component.ts file.

// app.component.ts

import { Component, OnInit } from '@angular/core';
import {  FileUploader, FileSelectDirective } from 'ng2-file-upload/ng2-file-upload';

const URL = 'http://localhost:4000/api/upload';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit {
  title = 'ng8fileupload';
  public uploader: FileUploader = new FileUploader({ url: URL, itemAlias: 'photo' });
  ngOnInit() {
    this.uploader.onAfterAddingFile = (file) => { file.withCredentials = false; };
    this.uploader.onCompleteItem = (item: any, response: any, status: any, headers: any) => {
         console.log('ImageUpload:uploaded:', item, status, response);
         alert('File uploaded successfully');
    };
 }
}

In the above code, we have imported FileUploader and FileSelectDirective from ng2-file-upload.

Also, we have defined the backend API URL, which is http://localhost:4000/api/upload.

We will create a backend server in Node.js and then send a POST request to the server.

So, here we have used the Angular Component lifecycle. The function is ngOnInit().

We have written the file upload code inside the ngOnInit function.

Now, the only thing remaining is written the HTML code for the file upload component.

Write the following piece code inside the app.component.html file.

<div class="container">
  <input type="file" name="photo" ng2FileSelect [uploader]="uploader" />
  <button type="button" class="btn btn-success btn-s" 
    (click)="uploader.uploadAll()" 
    [disabled]="!uploader.getNotUploadedItems().length" >
        Upload an Image
  </button>
</div>

Now, go to the http://localhost:4200/ URL and see the output.

 

Install an ng-file-upload library

Now the only thing remaining is to create a backend in Node.js.

#Create Node.js backend

First, install the following node modules.

npm install express multer body-parser dotenv --save

Install nodemon as a dev dependency.

npm install nodemon --save-dev

Create a new directory inside root of angular project called uploads.

Okay, now create one file in the angular project root folder called server.js.

Write the following piece code inside the server.js file.

// server.js

const path = require('path');
const express = require('express');
const multer = require('multer');
const bodyParser = require('body-parser')
const app = express();

const DIR = './uploads';
 
let storage = multer.diskStorage({
    destination: (req, file, cb) => {
      cb(null, DIR);
    },
    filename: (req, file, cb) => {
      cb(null, file.fieldname + '-' + Date.now() + '.' + path.extname(file.originalname));
    }
});
let upload = multer({storage: storage});

app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended: true}));
 
app.use(function (req, res, next) {
  res.setHeader('Access-Control-Allow-Origin', 'http://localhost:4200');
  res.setHeader('Access-Control-Allow-Methods', 'POST');
  res.setHeader('Access-Control-Allow-Headers', 'X-Requested-With,content-type');
  res.setHeader('Access-Control-Allow-Credentials', true);
  next();
});
 
app.get('/api', function (req, res) {
  res.end('file catcher example');
});
 
app.post('/api/upload',upload.single('photo'), function (req, res) {
    if (!req.file) {
        console.log("No file received");
        return res.send({
          success: false
        });
    
      } else {
        console.log('file received');
        return res.send({
          success: true
        })
      }
});
 
const PORT = process.env.PORT || 4000;
 
app.listen(PORT, function () {
  console.log('Node.js server is running on port ' + PORT);
});

First, we have used process.env. Working with environment variables is a great way to configure different configurations of your Node.js application.

If the environment variable PORT is defined inside the .env file, then it will take that variable’s value; otherwise, it will pick the value of by default, and in our case, it is 4000. So node.js will spin up on the port 4000.

We have imported the multer library. It is the node.js compatible library to handling file or image handling in the node.js.

We can store the file using the multer’s file storage function.

When the HTTP POST request of the file is coming to the node.js server, then first we have used the body-parser module which parses the request data and then go to the multer function and extract the file from the request and add the timestamp to the filename and save the file inside the uploads directory. We have already defined the directory.

The final step is to start the node.js server using the following code.

nodemon server

Now, go to the frontend and try to upload a file. I have tried to upload an image, and it is successfully uploaded. You can see the alert() on the frontend.

 

Create Node.js backend

This is the primary example of Image Upload in Angular 8. If you want to resize the image using the node.js, then check out my Node.js image resize tutorial.

Also, see the uploads folder to see if the image is saved or not.

You can find more options on ng2-file-upload official documentation.

Finally, Angular 8 File Upload Tutorial With Example | Angular Image Upload is over. Thanks for taking it.

Recommended Posts

Angular 8 HttpClient Example

Angular 8 Observables Example

Angular NgFor Tutorial With Example

Angular NgStyle Tutorial With Example

Angular NgModel Directive Example

Angular NgClass Tutorial With Example

The post Angular 8 File Upload Example | Angular Image Upload appeared first on AppDividend.

]]>
https://appdividend.com/2019/06/07/angular-8-file-upload-tutorial-with-example-angular-image-upload/feed/ 7
Angular 8 HttpClient Example | How To Send AJAX Request https://appdividend.com/2019/06/06/angular-8-httpclient-example-how-to-send-ajax-request-in-angular/ https://appdividend.com/2019/06/06/angular-8-httpclient-example-how-to-send-ajax-request-in-angular/#respond Thu, 06 Jun 2019 10:42:08 +0000 http://localhost/wordpress/?p=8114 Angular 8 HttpClient Example | How To Send AJAX Request in Angular

Angular 8 HttpClient Example | How To Send AJAX Request in Angular is today’s topic. Right now, the latest version of Angular framework is Angular 8. If you are new to Angular 8, then check out my Angular 8 Tutorial in this blog. Most front-end applications communicate with the backend services over an HTTP protocol. […]

The post Angular 8 HttpClient Example | How To Send AJAX Request appeared first on AppDividend.

]]>
Angular 8 HttpClient Example | How To Send AJAX Request in Angular

Angular 8 HttpClient Example | How To Send AJAX Request in Angular is today’s topic. Right now, the latest version of Angular framework is Angular 8. If you are new to Angular 8, then check out my Angular 8 Tutorial in this blog. Most front-end applications communicate with the backend services over an HTTP protocol. Modern browsers support the two different APIs for making HTTP requests.

  1. XMLHttpRequest interface and the 
  2. fetch() API.

We will use XMLHttpRequest for Angular application.

Angular 8 HttpClient Example

The HttpClient in @angular/common/Http offers the simplified client HTTP API for Angular applications that rests on a XMLHttpRequest interface exposed by browsers. Additional benefits of the HttpClient include testability features, typed request and response objects, request and response interception, Observable apis, and streamlined error handling.

#Angular HTTP module

The Angular HTTP module all have the RxJS Observable-based API. What this means is that the multiple calls to the HTTP module will all return the observable, that we need to subscribe to one way or the other way.

Here are some key points to bear in mind that a particular type of Observables returned by an HTTP module.

  1. If we don’t subscribe to the observables, nothing will happen.
  2. If we subscribe the multiple times to these observables, multiple HTTP requests will be triggered (see this post for more details).
  3. This particular type of Observables are the single-value streams: If an HTTP request is successful, these observables will emit only one value and then complete.
  4. These observables will emit the error if the HTTP request fails, more on this later.

#Setup Angular 8 Project

We have already set up an Angular CLI, and now we need to create a project using the following command.

ng new ng8crud

It will create a new project and install the required files to set up the boilerplate.

#Import HttpClientModule

Before you can use a HttpClient, you need to import an Angular HttpClientModule. Most apps do import in the root AppModule.

// app.module.ts

import { NgModule }         from '@angular/core';
import { BrowserModule }    from '@angular/platform-browser';
import { HttpClientModule } from '@angular/common/http';

@NgModule({
  imports: [
    BrowserModule,
    // import HttpClientModule after BrowserModule.
    HttpClientModule,
  ],
  declarations: [
    AppComponent,
  ],
  bootstrap: [ AppComponent ]
})
export class AppModule {}

#Create Service File

In Angular application, it is a best practice to create a service file related to a particular module.

If an angular app needs to interact with the back end server, then we can write the API calling code inside the service file.

So, if we need to send a POST request to the server, then we import the HttpClient inside the service file and make an AJAX request to the server with the data object. After a successful request, the server sends a response back to the client.

You typically post-process the data, add the error handling logic, and maybe some retry logic to cope with an intermittent connectivity.

The component quickly becomes cluttered with the data access. The component becomes harder to understand, even harder to test, and the data access logic can’t be re-used or standardized.

That’s why it is the best practice to separate presentation of the data from data access by encapsulating the data access in the separate service and delegating to that service in a component.

So, now create a service file by the following command.

ng g s config

Now, write the following code inside the config.service.ts file.

// config.service.ts

import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';

@Injectable()
export class ConfigService {
  constructor(private http: HttpClient) { }
}

#Create a backend Server

We need the fake data to work with and that is why I am using one package called json-server for this tutorial. Okay, so let us install the package using the Yarn package manager.

yarn global add json-server

# or

npm install -g json-server

Now we need to create the folder inside src directory called data and in that folder, create one file called db.json. Let us add the following data inside the db.json file.

{
    "characters": [
    {
        "id": "1",
        "name": "Peter Dinklage",
        "age": "45"
    },
    {
        "id": "2",
        "name": "Lina Heady",
        "age": "43"
    },
    {
        "id": "3",
        "name": "Emilia Clarke",
        "age": "30"
    },
    {
        "id": "4",
        "name": "Kit Harrington",
        "age": "30"
    },
    {
        "id": "5",
        "name": "Sean Bean",
        "age": "50"
    }]
}

Now, start the JSON server using the following command.

json-server --watch src/data/db.json --port 4000

Now, we have the server running that can feed our data to our React Bootstrap Application.

Our JSON server is started at port: 4000 and URL is http://localhost:4000/characters.

#Send AJAX request to the server in Angular

We have created a backend server and also created a service file.

Now, we need to write the code that sends a GET request to the json server.

So, write the following code inside the config.service.ts file.

// config.service.ts

import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';

@Injectable()
export class ConfigService {
  constructor(private http: HttpClient) { }
  url = 'http://localhost:4000';
  getCharacters() {
    return this
            .http
            .get(`${this.url}/characters`);
  }
}

And here is the example of a small service that queries the database above using an HTTP GET, and fetch the data. This data then goes to the related component and using HTML, and we can show the data on the screen.

The above example is using the HTTP module in a small service file, that is displaying a list of characters. Let’s break down the following example step-by-step:

  1. We are using the new HttpClient client module, and injecting it in the constructor/
  2. Then we are calling the get() method, which is returning the data.

The HttpClient.get() method parsed a JSON server response into an anonymous Object type. It doesn’t know what a shape or attributes of that object is.

You can tell the HttpClient the type of response to make consuming the output easier and more prominent.

First, define the interface with the Characters attribute.

export interface Characters {
    id: Number;
    name: String;
    age: Number;
}

Then, specify that interface as an HttpClient.get() call’s type parameter in the service.

HTTP Headers

If we want to add the custom HTTP Headers in our HTTP request then, in addition to the headers the browser already attaches automatically. We can do this by using the HttpHeaders class.

const headers = new HttpHeaders()
            .set("X-CustomHeader", "custom header value");

getCharacters() { 
   return this 
          .http
          .get(`${this.url}/characters`, {headers}); }

As we can see, HttpHeaders also has an immutable API, and we are passing a configuration object as the second argument of the get() call.

This configuration object only has one property named headers, just like the local const that we defined – so we used the object short-hand creation notation to describe the configuration object.

#HTTP PUT request in Angular

Just like in the case of GET request, we can also use the Angular HTTP Client to do all the other available HTTP methods, namely the methods typically used for data modification such as PUT.

The PUT method should only be used if we want to replace the value of the resource.

#HTTP PATCH request in Angular

Most often than not, instead of providing the complete new version of the resource, what we want to do is to update a single property. And this is the primary use case for the use of the HTTP PATCH method.

The PATCH request is useful in situations where there is some further server-side modification of the patched values, such for example via a database trigger or a Firebase rule.

#HTTP DELETE request in Angular

Another frequent operation that we want to do is to trigger the logical delete of some data. This operation can completely wipe the data from our database or mark some data as deleted.

#HTTP POST request in Angular

If the operation that we are trying to do does not fit the description of any of the methods above (GET, PUT, PATCH, DELETE), then we can use an HTTP wildcard modification operation: POST.

That operation is typically used to add the new data to the database, although there are many other use cases.

Finally, Angular 8 HttpClient Example | How To Send AJAX Request in Angular is over.

Recommended Posts

Angular Modal Tutorial With Example

Angular 8 File Upload Example

Angular 8 NgClass Example

Angular 8 Forms Tutorial

Angular NgFor Example

The post Angular 8 HttpClient Example | How To Send AJAX Request appeared first on AppDividend.

]]>
https://appdividend.com/2019/06/06/angular-8-httpclient-example-how-to-send-ajax-request-in-angular/feed/ 0
Angular 8 Tutorial | Learn Angular 8 CRUD Example https://appdividend.com/2019/06/04/angular-8-tutorial-with-example-learn-angular-8-crud-from-scratch/ https://appdividend.com/2019/06/04/angular-8-tutorial-with-example-learn-angular-8-crud-from-scratch/#comments Tue, 04 Jun 2019 13:58:00 +0000 http://localhost/wordpress/?p=7979 Angular 8 Tutorial With Example | Learn Angular 8 CRUD From Scratch

In this Angular 8 CRUD Example topic,  You will learn Angular Tutorial with a brief example by building a full-stack CRUD — Create, Read, Update, and Delete web application. We will use Node.js as a platform and Express.js, which is a web framework built on top of Node.js, and MongoDB as a NoSQL Database. #New […]

The post Angular 8 Tutorial | Learn Angular 8 CRUD Example appeared first on AppDividend.

]]>
Angular 8 Tutorial With Example | Learn Angular 8 CRUD From Scratch

In this Angular 8 CRUD Example topic,  You will learn Angular Tutorial with a brief example by building a full-stack CRUD — Create, Read, Update, and Delete web application. We will use Node.js as a platform and Express.js, which is a web framework built on top of Node.js, and MongoDB as a NoSQL Database.

#New Features of Angular 8

The new features of Angular 8 are the following.

  1. TypeScript 3.8 Support.
  2. Web Workers.
  3. Preview of Ivy Rendering Engine.
  4. Dynamic imports for lazy-loaded modules.

You check out the new features in brief on my Angular 8 New Features post.

#What we build in this Angular 8 demo

This tutorial is specially designed for newcomers, and it will help you to up and running with the latest version of Angular, which is right now 8. 

#Prerequisites

  1. You have installed Node.js version > 10. NPM will be in use by default. I am using Node version 11.3.0
  2. You have installed MongoDB on your machine.

#Workflow of Angular 8 CRUD Example

We will create two separate projects. One is for Angular Frontend, and one is for Node.js and Express. That means one for frontend and one for the backend.

We will create the backend API, which deals with storing, modifying, and deleting the form values, and the frontend will consume that API; for example, it shows the data from the backend.

For this example, I am using the following tech stacks with their versions.

  1. Node v11.3.0
  2. NPM v6.9.0
  3. AngularCLI v8.0.1
  4. MongoDB shell version v3.6.3
  5. MongoDB version v3.6.3
  6. Mac OS Mojave

In this blog, I have previously written Angular 7 CRUD and Angular 6 CRUD tutorials in deep. Now, the Angular community has released the next version, which is Angular 8. If you do not know how to upgrade Angular CLI to version 8, then check out my Angular CLI 8 upgrade tutorial. In this MEAN Stack tutorial, we will see Angular Routing, Angular Forms, and on the back end side, we use Node.js and Express.js to handle the data and to store the data, we will use MongoDB.

#Angular 8 Example

In this tutorial, we will use the Angular 8. So if you are not so sure what Angular CLI version you are using, then type the following command, which will tell us the Angular CLI version.

ng --version

Angular 8 Tutorial With Example

#Project Description

We will create a demo project, where a user can save their ProductName, Product Description, and ProductPrice from the Angular form and submit the form to the node.js server. If the values are incorrect, then it will validate at the frontend, and the form will not submit.

We will not validate the field values at the backend because it will make this tutorial more lengthy. If you want to create a validation at the backend, then check out my express form validation tutorial.

If all the values are perfect, then it will send the form values to the Node.js backend API, and it will store the values inside the MongoDB database.

#Step 1: Create An Angular Boilerplate

Let’s create an Angular 8 project using the following command.

Create Angular 8 Project

When you install a brand new Angular project, see the options they are providing while creating a new project. In this project, we need the routing module, so we will allow the Angular CLI to create a routing module for us.

I am using Visual Studio Code as a programming editor to develop Angular application.

Now, go inside the folder and open the project inside the VSCode.

cd angular8tutorial
code .

At the time of installation, we have enabled routing for our angular app. You can check the file called app-routing.module.ts file inside src >> app directory.

Next, install the Bootstrap 4 CSS Framework using the following command. It is not a necessary step, and you can choose your CSS Framework as well.

npm install bootstrap --save

Now, add it inside an angular.json file.

"styles": [
   "src/styles.css",
   "./node_modules/bootstrap/dist/css/bootstrap.min.css"
 ],

It will include a bootstrap CSS file, and we can use the bootstrap classes inside any file.

Start an Angular development server using the following command.

ng serve -o

The server starts at the http://localhost:4200/. You can see the output in the browser. It is an initial Angular home screen.

#Step 2: Generate The Angular Components

Hit the following command to generate the Angular Components. We will perform to create, read, update operations. So we will create three components.

ng g c product-add --skipTests=true
ng g c product-get --skipTests=true
ng g c product-edit --skipTests=true
Option “spec” is deprecated in Angular 8: Use “skipTests” instead.
For this demo, we do not need the tests file. So, we will not create it.
All the three components are automatically registered inside an app.module.ts file. Now, we need to configure the routing of angular components inside an app-routing.module.ts file.

Now, you can see an app-routing.module.ts file inside the src >> app folder file. It is created because while we were installing the angular app, we permitted angular cli to generate the routing file for us.

All the three components are automatically registered inside an app.module.ts file. Now, we need to import and configure the routing of angular components inside the app-routing.module.ts file.

Write the following code inside an app-routing.module.ts file.

// app-routing.module.ts

import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { ProductAddComponent } from './product-add/product-add.component';
import { ProductEditComponent } from './product-edit/product-edit.component';
import { ProductGetComponent } from './product-get/product-get.component';

const routes: Routes = [
  {
    path: 'product/create',
    component: ProductAddComponent
  },
  {
    path: 'edit/:id',
    component: ProductEditComponent
  },
  {
    path: 'products',
    component: ProductGetComponent
  }
];

@NgModule({
  imports: [RouterModule.forRoot(routes)],
  exports: [RouterModule]
})
export class AppRoutingModule { }

Now, you can see inside the app.component.html file that <router-outlet> directive is there. This directive helps us to render the different components based on route URI.

#Step 3: Create The Angular Navigation

Write the following code inside the app.component.html file.

<nav class="navbar navbar-expand-sm bg-light">
  <div class="container-fluid">
    <ul class="navbar-nav">
      <li class="nav-item">
        <a routerLink="product/create" class="nav-link" routerLinkActive="active">
          Create Product
        </a>
      </li>
      <li class="nav-item">
        <a routerLink="products" class="nav-link" routerLinkActive="active">
          Products
        </a>
      </li> 
    </ul>
  </div>
</nav>

<div class="container">
  <router-outlet></router-outlet>
</div>

Save the file and go to the browser and click on two links. You can see that we can see the different components based on navigation.

Create an Angular Navigation

#Step 4: Configure Angular Routing Progress Indicator.

Type the following command to install the ng2-slim-loading-bar library.

npm install ng2-slim-loading-bar --save

So, if you install the third-party packages right now, then it is not compatible with an Angular 8. If we want to bridge the gap between Angular 8 and the third-party packages, we need to install the following library. That is it.

npm install rxjs-compat --save

Now, import the SlimLoadingBarModule inside an app.module.ts file.

// app.module.ts

import { SlimLoadingBarModule } from 'ng2-slim-loading-bar';

imports: [
    ...
    SlimLoadingBarModule
],

The next step is, include the styling that comes with the library inside src  >>  styles.css file.

@import "../node_modules/ng2-slim-loading-bar/style.css";

#Step 5: Add Router Events.

Angular RouterModule gives us the following event modules.

  1. NavigationStart
  2. NavigationEnd
  3. NavigationError
  4. NavigationCancel
  5. Router
  6. Event

Now, write the following code inside the  app.component.ts file.

// app.component.ts

import { Component } from '@angular/core';
import {SlimLoadingBarService} from 'ng2-slim-loading-bar';
import { NavigationCancel,
        Event,
        NavigationEnd,
        NavigationError,
        NavigationStart,
        Router } from '@angular/router';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  title = 'angular8tutorial';
  constructor(private loadingBar: SlimLoadingBarService, private router: Router) {
    this.router.events.subscribe((event: Event) => {
      this.navigationInterceptor(event);
    });
  }
  private navigationInterceptor(event: Event): void {
    if (event instanceof NavigationStart) {
      this.loadingBar.start();
    }
    if (event instanceof NavigationEnd) {
      this.loadingBar.complete();
    }
    if (event instanceof NavigationCancel) {
      this.loadingBar.stop();
    }
    if (event instanceof NavigationError) {
      this.loadingBar.stop();
    }
  }
}

In the above code, we have told the Angular application that while we navigate from one component to another component, while we want to display the router progress indicator. 

When a user clicks the other route, the angular progress indicator start showing, and when the navigation is complete, it will stop displaying. So, it is a kind of best User experience for the user.

What it is doing in the code that it intercepts the routing event and add the loading bar component to the loading route so that we can see the routing indication every time we change the routes.

The final change is to display the routing indicator is that we need to insert an ng2-slim-loading-bar directive inside the app.component.html file at the top of the page.

<!-- app.component.html -->

<ng2-slim-loading-bar color="blue"></ng2-slim-loading-bar>
<nav class="navbar navbar-expand-sm bg-light">
  <div class="container-fluid">
    <ul class="navbar-nav">
      <li class="nav-item">
        <a routerLink="product/create" class="nav-link" routerLinkActive="active">
          Create Product
        </a>
      </li>
      <li class="nav-item">
        <a routerLink="products" class="nav-link" routerLinkActive="active">
          Products
        </a>
      </li> 
    </ul>
  </div>
</nav>

<div class="container">
  <router-outlet></router-outlet>
</div>

Save the file and go to the terminal to see if there any error, and if there is no error, then go to the browser and change the routes, and you can see that now we can see the routing indicator while changing the different angular routes.

#Step 6: Add The Bootstrap To HTML Form

Inside the product-add.component.html file, add the following bootstrap 4 form. We have three HTML fields for this demo.

<!-- product-add.component.html -->

<div class="card">
  <div class="card-body">
    <form>
      <div class="form-group">
        <label class="col-md-4">Product Name</label>
        <input type="text" class="form-control" />
      </div>
      <div class="form-group">
        <label class="col-md-4">Product Description </label>
        <textarea class="form-control" rows = 7 cols = "5"></textarea>
      </div>
      <div class="form-group">
        <label class="col-md-4">Product Price</label>
        <input type="text" class="form-control" />
      </div>
      <div class="form-group">
        <button type="submit" class="btn btn-primary">Create Product</button>
      </div>
    </form>
  </div>
</div>

Add Bootstrap Form

#Step 7: Create Angular 8 Form Validation

For form validation, we have two options. Template-based and Reactive Forms Module. We will use the ReactiveFormsModule approach. Now, if you are new to Angular Form Validation, then please check out my this article Angular Form Validation Example Tutorial on this blog.

Now, import the ReactiveFormsModule inside the app.module.ts file. It comes with an Angular project by default.

// app.module.ts

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

imports: [
    ...
    ReactiveFormsModule
],

Now, we need to write a code for the app.component.ts file. Remember, this is not the template-driven form. So we need to add the code inside the app.component.ts file.

First, we import the FormGroup, FormBuilder, Validators modules from @angular/forms.

Also, create a constructor and instantiate the FormBuilder.

So write the following code inside the product-add.component.ts file.

// product-add.component.ts

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

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

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

  createForm() {
    this.angForm = this.fb.group({
      ProductName: ['', Validators.required ],
      ProductDescription: ['', Validators.required ],
      ProductPrice: ['', Validators.required ]
    });
  }

  ngOnInit() {
  }

}

We have used a form builder to handle all the validation. So in that constructor, we are creating the form with all the validation rules for particular fields. In our example, there are three fields. If the input text is empty, then it will give an error, and we need to display that error.

Now, write the following code inside the product-add.component.html file.

<!-- product-add.component.html -->

<div class="card">
  <div class="card-body">
    <form [formGroup]="angForm" novalidate>
      <div class="form-group">
        <label class="col-md-4">Product Name</label>
        <input type="text" class="form-control" 
          formControlName="ProductName" 
          #ProductName />
      </div>
      <div *ngIf="angForm.controls['ProductName'].invalid && (angForm.controls['ProductName'].dirty || angForm.controls['ProductName'].touched)" class="alert alert-danger">
        <div *ngIf="angForm.controls['ProductName'].errors.required">
          Product Name is required.
        </div>
      </div>
      <div class="form-group">
        <label class="col-md-4">Product Description </label>
        <textarea class="form-control" rows = 7 cols = "5"
        formControlName="ProductDescription" 
        #ProductDescription></textarea>
      </div>
      <div *ngIf="angForm.controls['ProductDescription'].invalid && (angForm.controls['ProductDescription'].dirty || angForm.controls['ProductDescription'].touched)" class="alert alert-danger">
        <div *ngIf="angForm.controls['ProductDescription'].errors.required">
          Product Description is required.
        </div>
      </div>
      <div class="form-group">
        <label class="col-md-4">Product Price</label>
        <input type="text" class="form-control" 
          formControlName="ProductPrice" 
          #ProductPrice
        />
      </div>
      <div *ngIf="angForm.controls['ProductPrice'].invalid && (angForm.controls['ProductPrice'].dirty || angForm.controls['ProductPrice'].touched)" class="alert alert-danger">
        <div *ngIf="angForm.controls['ProductPrice'].errors.required">
          Product Price is required.
        </div>
      </div>
      <div class="form-group">
        <button type="submit" class="btn btn-primary"
        [disabled]="angForm.pristine || angForm.invalid" >
          Create Product
        </button>
      </div>
    </form>
  </div>
</div>

Save the file and go to the browser, and you can see if you do not put any value inside the input box, then you will see the errors.

Add Angular 8 Form Validation

#Step 8: Add And Configure the HttpClientModule

Most front-end applications communicate with the backend services over an HTTP protocol. Modern browsers support the two different APIs for making HTTP requests: the XMLHttpRequest interface and the fetch API.

The HttpClient in @angular/common/http offers a simplified client HTTP API for Angular applications that rests on the XMLHttpRequest interface exposed by browsers. Additional benefits of the HttpClient include the testability features, typed request and response objects, request and response interception, the Observables APIs, and smooth error handling.

Import the HttpClientModule inside an app.module.ts file.

// app.module.ts

import { HttpClientModule } from '@angular/common/http';

imports: [
   ...
    HttpClientModule
 ],

#Step 9: Create A TypeScript Model file.

Inside the src >> app folder, create one file called Product.ts and add the following code.

// Product.ts

export default class Product {
  ProductName: string;
  ProductDescription: string;
  ProductPrice: number;
}

#Step 10: Create An Angular Service file.

Type the following command to generate the service file.

The primary use of the service file is that we are adding all of our AJAX code inside that file. So, it sends an ajax request to the backend server and retrieves the data from the backend server.

ng g service products --skipTests=true

So, your necessary products.service.ts file looks like this.

// products.service.ts

import { Injectable } from '@angular/core';

@Injectable({
  providedIn: 'root'
})
export class ProductsService {

  constructor() { }
}

Now, import the products.service.ts file into the app.module.ts file.

// app.module.ts

import { ProductsService } from './products.service';

providers: [ ProductsService ],

#Step 11: Submit Form Values To Node Server

Now, we need to write the code that will send the HTTP POST request with the data to the Node.js server and store the data into the MongoDB database.

Write the following code inside the products.service.ts file.

// products.service.ts

import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';

@Injectable({
  providedIn: 'root'
})
export class ProductsService {

  uri = 'http://localhost:4000/products';

  constructor(private http: HttpClient) { }

  addProduct(ProductName, ProductDescription, ProductPrice) {
    const obj = {
      ProductName,
      ProductDescription,
      ProductPrice
    };
    console.log(obj);
    this.http.post(`${this.uri}/add`, obj)
        .subscribe(res => console.log('Done'));
  }
}

We have defined our backend API URL, but we have not created any backend yet, but we will do it in the following couple of steps.

Now, we need to add the click event to the Add Product Button. So add the following code inside a product-add.component.html file.

<div class="form-group">
        <button (click) = "addProduct(ProductName.value, ProductDescription.value, ProductPrice.value)" type="submit" class="btn btn-primary"
        [disabled]="angForm.pristine || angForm.invalid" >
          Create Product
        </button>
</div>

So when there are no errors, we can submit the form, and it will call the component’s addPropduct function. From there, we will call the angular service, and the service will send the HTTP Post request to the Node.js server.

Now, add the addProduct function inside the product-add.component.ts file. So write the following code inside the product-add.component.ts file.

// product-add.component.ts

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

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

  angForm: FormGroup;
  constructor(private fb: FormBuilder, private ps: ProductsService) {
    this.createForm();
  }

  createForm() {
    this.angForm = this.fb.group({
      ProductName: ['', Validators.required ],
      ProductDescription: ['', Validators.required ],
      ProductPrice: ['', Validators.required ]
    });
  }

  addProduct(ProductName, ProductDescription, ProductPrice) {
    this.ps.addProduct(ProductName, ProductDescription, ProductPrice);
  }

  ngOnInit() {
  }

}

In the above code, first, I have imported the products.service.ts file. Then we have defined the addProduct method.

This method is called when the user clicks on the create product button, and the flow will transfer over here. We get the ProductName, ProductDescription, and ProductPrice data inside the addProduct function.

Inside that function, we are calling the products.service.ts file’s addProduct function and pass the three parameters with it.

So, from the products.service.ts file will call the API and save the products on the server. Now, we need to configure the backend API.

#Step 12: Create A Backend API In Node.js

Inside the angular root folder, create one folder called the API and go inside that folder. Remember, it will be a completely separate project from the Angular frontend project. So its node_modules folders are different from the Angular project.

Open a terminal inside the API folder and type the following command. It will generate the package.json file using NPM. We do not want to specify each option one by one; that is why we are typing the following command.

npm init -y

Install the following node-specific modules.

npm install express body-parser cors mongoose --save

I do not want to restart the node server each time; I change the file. So I am installing the nodemon server. What it does is that, when I modify a server.js file, it restarts a node.js server automatically.

npm install nodemon --save-dev

We are also installing the body-parser module to parse the data from the incoming Http request.

We have installed the CORS module because our both angular and node application is running on the different ports.

The browser will not allow the CROSS REQUEST ORIGIN attack; that is why we need to install the CORS module to receive the proper request at the backend server.

We have installed the Mongoose module because it provides the ORM for the MongoDB database.

Now, inside the API folder, create one file called server.js file. Add the following code inside that file.

// server.js

const express = require('express'),
    path = require('path'),
    bodyParser = require('body-parser'),
    cors = require('cors'),
    mongoose = require('mongoose');

    const app = express();
    let port = process.env.PORT || 4000;

    const server = app.listen(function(){
        console.log('Listening on port ' + port);
    });

The next thing is to connect the MongoDB database with our node express application.

If you have not installed a MongoDB database, then install it and then start the MongoDB server using the following command.

mongod

So, Now, I have connected to a database.

Create one file called DB.js inside the api root project folder. Write the following code inside a DB.js file.

// DB.js

module.exports = {
  DB: 'mongodb://localhost:27017/ng8crud'
};

Import this DB.js file inside our server.js file and use the Mongoose library to set up the database connection with MongoDB. We can also use the Mongoose to save the data in the database using the Mongoose ORM.

Write the following code inside a server.js file to connect our MongoDB application to a Node.js server.

// server.js

const express = require('express'),
    path = require('path'),
    bodyParser = require('body-parser'),
    cors = require('cors'),
    mongoose = require('mongoose'),
    config = require('./DB');

    mongoose.Promise = global.Promise;
    mongoose.connect(config.DB, { useNewUrlParser: true }).then(
      () => {console.log('Database is connected') },
      err => { console.log('Can not connect to the database'+ err)}
    );

    const app = express();
    app.use(bodyParser.json());
    app.use(cors());
    const port = process.env.PORT || 4000;

    const server = app.listen(port, function(){
     console.log('Listening on port ' + port);
    });

Save the above server.js file and go to the terminal and start the node server using the following command. Remember, we are using nodemon.

nodemon server

So, right now, you have three servers running.

  1. Angular Development Server for frontend.
  2. Nodemon server for the backend.
  3. MongoDB server for database.

Remember, all three servers are running fine without any error; otherwise, our application will not work, and it will crash.

#Step 13: Create Route And Model Files.

Now, we need to create two folders inside the api root folder called routes and models.

In the models’ folder, create one model called Product.js.

// Product.js

const mongoose = require('mongoose');
const Schema = mongoose.Schema;

// Define collection and schema for Product
let Product = new Schema({
  ProductName: {
    type: String
  },
  ProductDescription: {
    type: String
  },
  ProductPrice: {
    type: Number
  }
},{
    collection: 'Product'
});

module.exports = mongoose.model('Product', Product);

So, we have defined our schema for the Product collection. We have three fields called ProductName, ProductDescription, ProductPrice.

In the routes folder, create one file called the product.route.js.

Write the CRUD code inside the product.route.js file.

// product.route.js

const express = require('express');
const app = express();
const productRoutes = express.Router();

// Require Product model in our routes module
let Product = require('../models/Product');

// Defined store route
productRoutes.route('/add').post(function (req, res) {
  let product = new Product(req.body);
  product.save()
    .then(product => {
      res.status(200).json({'Product': 'Product has been added successfully'});
    })
    .catch(err => {
    res.status(400).send("unable to save to database");
    });
});

// Defined get data(index or listing) route
productRoutes.route('/').get(function (req, res) {
  Product.find(function (err, products){
    if(err){
      console.log(err);
    }
    else {
      res.json(products);
    }
  });
});

// Defined edit route
productRoutes.route('/edit/:id').get(function (req, res) {
  let id = req.params.id;
  Product.findById(id, function (err, product){
      res.json(product);
  });
});

//  Defined update route
productRoutes.route('/update/:id').post(function (req, res) {
  Product.findById(req.params.id, function(err, product) {
    if (!product)
      res.status(404).send("Record not found");
    else {
      product.ProductName = req.body.ProductName;
      product.ProductDescription = req.body.ProductDescription;
      product.ProductPrice = req.body.ProductPrice;

      product.save().then(product => {
          res.json('Update complete');
      })
      .catch(err => {
            res.status(400).send("unable to update the database");
      });
    }
  });
});

// Defined delete | remove | destroy route
productRoutes.route('/delete/:id').get(function (req, res) {
    Product.findByIdAndRemove({_id: req.params.id}, function(err, product){
        if(err) res.json(err);
        else res.json('Successfully removed');
    });
});

module.exports = productRoutes;

Here, we have used the mongoose model to save, update, delete the data from the database. Mongoose is an ORM used in the MongoDB database. It will handle all the CRUD task at the backend. Now, we have all the CRUD operations functions set up on the route file. The final thing is that we need to import inside the server.js file.

Remember, the server.js file is the starting point of our backend node application. So every module needs to be included inside the server.js file.

So, our final server.js file looks like this.

// server.js

const express = require('express'),
    path = require('path'),
    bodyParser = require('body-parser'),
    cors = require('cors'),
    mongoose = require('mongoose'),
    config = require('./DB');

   const productRoute = require('./routes/product.route');
    mongoose.Promise = global.Promise;
    mongoose.connect(config.DB, { useNewUrlParser: true }).then(
      () => {console.log('Database is connected') },
      err => { console.log('Can not connect to the database'+ err)}
    );

    const app = express();
    app.use(bodyParser.json());
    app.use(cors());
    app.use('/products', productRoute);
    const port = process.env.PORT || 4000;

    const server = app.listen(port, function(){
     console.log('Listening on port ' + port);
    });

Now, go to the terminal and start the node server if you have not already started.

node server

#Step 14: Save Data In MongoDB Database

If all of your servers are up and running, then you can go to the browser and fill the form data and add the Product. You can see something like this on your screen if you are successful.

Sometimes, if you are running an adblocker on the browser, then it will not work. So please turn off the adblocker and try this example again.

Test the store data functionality

Now, we can check on the database using the following commands.

First, open the mongo shell on the 4th tab because all the other three tabs are occupied at the moment.

mongo

MongoDB Add

Here, we can see that the values are storing in the MongoDB database. Yess!! We have succeeded.

Now, remaining operations are Read, Update, and Delete.

#Step 15: Show The Data On Angular Frontend

We can iterate the backend data and display the data in the tabular format using Angular ngfor directive.

Inside the product-get.component.html file, write the following code.

<!-- product-get.component.html -->

<table class="table table-hover">
  <thead>
  <tr>
      <td>Product Name</td>
      <td>Product Description</td>
      <td>Product Price</td>
      <td colspan="2">Actions</td>
  </tr>
  </thead>

  <tbody>
      <tr *ngFor="let product of products">
          <td>{{ product.ProductName }}</td>
          <td>{{ product.ProductDescription }}</td>
          <td>{{ product.ProductPrice }}</td>
          <td><a [routerLink]="['/edit', product._id]" class="btn btn-primary">Edit</a></td>
          <td><a [routerLink]="" class="btn btn-danger">Delete</a></td>
      </tr>
  </tbody>
</table>

Now, inside the products.service.ts file, we need to write the function that fetches the product data from the MongoDB database and display it at the Angular application.

// products.service.ts

getProducts() {
    return this
           .http
           .get(`${this.uri}`);
  }

In the above getProducts() function, we have sent the HTTP GET request to the Node.js server and fetch the data from the database.

Now, we need to include the products.service.ts file and Product.ts file inside a product-get.component.ts file.

Write the following code inside the product-get.component.ts file.

// product-get.component.ts

import { Component, OnInit } from '@angular/core';
import Product from '../Product';
import { ProductsService } from '../products.service';

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

  products: Product[];
  constructor(private ps: ProductsService) { }

  ngOnInit() {
    this.ps
      .getProducts()
      .subscribe((data: Product[]) => {
        this.products = data;
    });
  }

}

Save the file and go to the browser and switch to this URL: http://localhost:4200/products. You can see the listing of the products.

Display the data on the frontend

 

#Step 16: Edit And Update Fields

Okay, first, we need to fetch the data from the MongoDB database using _id wise and display that data in the product-edit.component.html file.

For that, when the product-edit.component.html loads, we send an AJAX request to the node server and fetch the particular row using the _id and display the data to their respective fields inside the HTML form.

So first, write the following code inside the product-edit.component.ts file.

// product-edit.component.ts

import { Component, OnInit } from '@angular/core';
import { FormGroup, FormBuilder, Validators } from '@angular/forms';
import { ActivatedRoute, Router } from '@angular/router';
import { ProductsService } from '../products.service';

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

  angForm: FormGroup;
  product: any = {};

  constructor(private route: ActivatedRoute, private router: Router, private ps: ProductsService, private fb: FormBuilder) {
      this.createForm();
 }

  createForm() {
    this.angForm = this.fb.group({
      ProductName: ['', Validators.required ],
      ProductDescription: ['', Validators.required ],
      ProductPrice: ['', Validators.required ]
    });
  }

  ngOnInit() {
    this.route.params.subscribe(params => {
        this.ps.editProduct(params['id']).subscribe(res => {
          this.product = res;
      });
    });
  }
}

Here, when the product-edit component.ts render, it will call the ngOnInit method and send an HTTP request to the node server and fetch the data from an _id to display inside the product-edit component.html file.

Now, inside the products.service.ts file, we need to code the editProduct function to send an HTTP request.

// products.service.ts

import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';

@Injectable({
  providedIn: 'root'
})
export class ProductsService {

  uri = 'http://localhost:4000/products';

  constructor(private http: HttpClient) { }

  addProduct(ProductName, ProductDescription, ProductPrice) {
    console.log(ProductName, ProductDescription, ProductPrice);
    const obj = {
      ProductName,
      ProductDescription,
      ProductPrice
    };
    this.http.post(`${this.uri}/add`, obj)
        .subscribe(res => console.log('Done'));
  }

  getProducts() {
    return this
           .http
           .get(`${this.uri}`);
  }

  editProduct(id) {
    return this
            .http
            .get(`${this.uri}/edit/${id}`);
    }
}

Now, finally, we need to write the form inside the product-edit.component.html file.

<!-- product-edit.component.html -->

<div class="card">
  <div class="card-body">
    <form [formGroup]="angForm" novalidate>
      <div class="form-group">
        <label class="col-md-4">Product Name</label>
        <input type="text" class="form-control" 
          formControlName="ProductName" 
          #ProductName 
          [(ngModel)] = "product.ProductName"/>
      </div>
      <div *ngIf="angForm.controls['ProductName'].invalid && (angForm.controls['ProductName'].dirty || angForm.controls['ProductName'].touched)" class="alert alert-danger">
        <div *ngIf="angForm.controls['ProductName'].errors.required">
          Product Name is required.
        </div>
      </div>
      <div class="form-group">
        <label class="col-md-4">Product Description </label>
        <textarea class="form-control" rows = 7 cols = "5"
        formControlName="ProductDescription" 
        #ProductDescription [(ngModel)] = "product.ProductDescription"></textarea>
      </div>
      <div *ngIf="angForm.controls['ProductDescription'].invalid && (angForm.controls['ProductDescription'].dirty || angForm.controls['ProductDescription'].touched)" class="alert alert-danger">
        <div *ngIf="angForm.controls['ProductDescription'].errors.required">
          Product Description is required.
        </div>
      </div>
      <div class="form-group">
        <label class="col-md-4">Product Price</label>
        <input type="text" class="form-control" 
          formControlName="ProductPrice" 
          #ProductPrice
          [(ngModel)] = "product.ProductPrice"
        />
      </div>
      <div *ngIf="angForm.controls['ProductPrice'].invalid && (angForm.controls['ProductPrice'].dirty || angForm.controls['ProductPrice'].touched)" class="alert alert-danger">
        <div *ngIf="angForm.controls['ProductPrice'].errors.required">
          Product Price is required.
        </div>
      </div>
      <div class="form-group">
        <button (click) = "updateProduct(ProductName.value, ProductDescription.value, ProductPrice.value)" type="submit" class="btn btn-primary"
        [disabled]="angForm.invalid" >
          Update Product
        </button>
      </div>
    </form>
  </div>
</div>

Save the file and go to the listing page and click on the edit button and you will see the populated form fields from the database.

You can also see the warning like the following. Ignore this demo tutorial.

forms.js:1193
It looks like you’re using ngModel on the same form field as formControlName.
Support for using the ngModel input property and ngModelChange event with
reactive form directives have been deprecated in Angular v6 and will be removed
in Angular v7.
Now, we need to update the data into the database.
Inside the products.service.ts file, we need to write a function that updates the form fields data. See the following code.
// products.service.ts

updateProduct(ProductName, ProductDescription, ProductPrice, id) {
    const obj = {
      ProductName,
      ProductDescription,
      ProductPrice
    };
    this
      .http
      .post(`${this.uri}/update/${id}`, obj)
      .subscribe(res => console.log('Done'));
}

Okay, now write the updateProduct() function inside product-edit.component.ts file.

// product-edit.component.ts

updateProduct(ProductName, ProductDescription, ProductPrice, id) {
    this.route.params.subscribe(params => {
      this.ps.updateProduct(ProductName, ProductDescription, ProductPrice, params.id);
      this.router.navigate(['products']);
    });
  }

In the above function, we get the form values from the HTML forms and sends the PUT request to the node server with the updated values, and at the backend, the update function will call and update the values inside the MongoDB database.

Save the file, and you will be able to update the data.

#Step 17: Delete Form Data.

So, if you find no error on the console, then you can successfully update the form data.

I have already written edit and update service to make API calls. So till now, we have completed the Create, Read, Update task of this Angular 8 Tutorial with CRUD Example post. Now, take a look at Delete or remove the data from the database.

Now, we need to define the click event on the delete button inside the product-get.component.html file.

<!-- product-get.component.html -->

<tbody>
      <tr *ngFor="let product of products">
          <td>{{ product.ProductName }}</td>
          <td>{{ product.ProductDescription }}</td>
          <td>{{ product.ProductPrice }}</td>
          <td><a [routerLink]="['/edit', product._id]" class="btn btn-primary">Edit</a></td>
          <td><a (click) = "deleteProduct(product._id)" class="btn btn-danger">Delete</a>
      </tr>
  </tbody>

Now, write the deleteProduct function inside the product-get.component.ts file.

// product-get.component.ts

deleteProduct(id) {
    this.ps.deleteProduct(id).subscribe(res => {
      this.products.splice(id, 1);
    });
}

The above function will send the ID to the server to delete the row from the database, and on the frontend, we are using the Javascript Splice function to remove the data from the Angular application.

Now, create deleteProduct() function inside the product.service.ts file. We will send an ID in this AJAx request to delete the data from the backend.

// products.service.ts

deleteProduct(id) {
    return this
              .http
              .get(`${this.uri}/delete/${id}`);
  }

Finally, I completed the delete data or remove data functionality.

So, in this tutorial, we have completed the CRUD Functionality in Angular 8. I have also put the code on Github.

If you have any doubt in this Angular 8 Tutorial With CRUD Example, then ask in a comment below. If I were busy, then some will surely reply to you.

GITHUB CODE

Recommended Posts

Angular 8 File Upload Tutorial

Angular 8 HttpClient Example

Angular 8 Updates And Summary

How To Update Angular CLI To Version 8

Angular 8 Forms Tutorial

Angular NgFor Tutorial With Example

Angular NgStyle Example

Angular Modal Tutorial With Example

Angular NgClass Example

Angular Drag and Drop Tutorial

The post Angular 8 Tutorial | Learn Angular 8 CRUD Example appeared first on AppDividend.

]]>
https://appdividend.com/2019/06/04/angular-8-tutorial-with-example-learn-angular-8-crud-from-scratch/feed/ 39
Angular 8 Updates And Summary of New Features https://appdividend.com/2019/05/31/angular-8-updates-and-summary-of-new-features/ https://appdividend.com/2019/05/31/angular-8-updates-and-summary-of-new-features/#respond Fri, 31 May 2019 11:47:21 +0000 http://localhost/wordpress/?p=7809 Angular 8 Updates And Summary of New Features

Angular 8 Updates And Summary of New Features is today’s topic. Angular 8 arrives with an impressive list of changes and improvements including the much-anticipated Ivy compiler as an opt-in feature. You can check out Angular 7 features and updates if you have not seen yet. In this blog, we have written some articles about […]

The post Angular 8 Updates And Summary of New Features appeared first on AppDividend.

]]>
Angular 8 Updates And Summary of New Features

Angular 8 Updates And Summary of New Features is today’s topic. Angular 8 arrives with an impressive list of changes and improvements including the much-anticipated Ivy compiler as an opt-in feature. You can check out Angular 7 features and updates if you have not seen yet. In this blog, we have written some articles about Angular 7 Crud, Angular 7 Routing, Angular ngClass, Angular ngFor.

Angular 8 Updates And Summary

See the following updates.

TypeScript 3.4

Angular 8.0 is now supported TypeScript 3.4, and even requires it, so you will need to upgrade.

You can look at what TypeScript 3.3 and TypeScript 3.4 brings on the table on official Microsoft blog.

What about Ivy and Bazel

We will have to wait for more for Ivy, the new rendering engine, and Bazel, the new build system, to be ready for proper use with an Angular.

An opt-in preview of the two should be available shortly.

Ivy is a massive part of this release, and it took most of the effort from a team these last month.

Ivy is a new compiler/runtime of Angular.

It will enable the cool features in the future, but it is currently focused on not to break any existing web applications.

Angular 8 is a first release to offer a switch to opt-in into Ivy officially.

There are no real gains to apply changes right now, but you can give it a try to see if nothing breaks in your angular application.

Because, at some point, probably in Angular version 9, Ivy will be the by default.

So the Angular team hopes that the community will anticipate a switch and provide the feedback and that we will catch all the remaining issues before Angular 9.

Brad Green, a technical director behind the Angular team at Google, mentions at ng-conf 2019 that Ivy will allow the noticeable improvement of bundle sizes in compatibility mode in combination with differential loading.

Thrill-seekers can thus already try out a future Ivy API.

Ivy mode contains a significant amount of potential for optimization explicitly. The API is still marked as a private though. You can tell by looking at the classes and functions as they start with a unique character ɵ.

One of the new features of Angular 8.0 is a possibility to (more quickly) build your CLI application with Bazel. The key advantages of Bazel are:

  1. The chance of making your backends and frontends with a same tool.
  2. The incremental build and tests.
  3. It has a possibility to have remote builds and cache on the build farm.

The second point is most useful for most developers. Bazel allows us to declare tasks with precise inputs and outputs.

Then when you run the command, Bazel builds the task graph, and only runs a necessary ones, depending on which the inputs and outputs changed since the last run (very similar to what the Gradle does in the Java world). This can bring an impressive gains on rebuild times.

This talk by Alex Eagle at ng-conf 2019 can be interesting to learn more about what Bazel can do.

Be warned though: the first build will be painfully slow, as Bazel is aiming for precisely reproducible builds. For example, if you launch your tests on the Firefox browser, it will download the complete version of Firefox, to make sure all developers are running the criteria in the same browser!

So if you want to launch the tests on the big project (like the Angular framework), you can grab the coffee. But after the first build, the change in the codebase will only trigger the smallest rebuild possible. It’s especially useful if your web application is made of several modules and libraries.

CLI workflow improvements

The CLI is continuing to improve, and now the ng build, ng test and ng run are equipped to be extended by 3rd-party libraries and tool. For example, AngularFire already makes use of these new capabilities with a deploy command.

Web workers

JavaScript is single threaded by definition. Because of this, it is common for more critical tasks like data calls to take place asynchronously. This doesn’t help with elaborate calculations. Those especially are becoming more and more common with an extensive JavaScript solutions, which is why we support the almost all browser web workers by now. They are the scripts that a browser runs in an own thread. Communication with a thread in the browser tab takes place via sending messages.

While web workers have nothing to do with Angular per se, they must be taken into consideration in the build. The goal is to provide one bundle for every web worker. The new Angular CLI accomplishes this task.

Web Workers allow you to run the CPU intensive computations in the background thread, freeing the main thread to update the user interface.

If you find your application becomes unresponsive while processing data, using Web Workers can help.

To outsource such a calculation to a background, we must first create the web worker using the Angular CLI.

ng generate worker n-queens

Dynamic imports for lazy routes

Lazy-loaded routes now use the standard dynamic import syntax instead of a custom string. This means that TypeScript and linters will be better able to complain when modules are missing or misspelled.

So a lazy-loaded import that looked like this.

{ path: '/student', loadChildren: './student/student.module#StudentModule' }

Will now look like this.

{ path: `/student`, loadChildren: () => import(`./student/student.module`).then(s => s.StudentModule) }

The change in syntax will be taken care of for you if you’re using the ng upgrade command to upgrade your app.

Differential loading

Your Angular 8 apps will now be automagically more performant, thanks to differential loading.

With differential loading, two bundles are created when building for production: a bundle for modern browsers that support ES2015+ and a bundle for older browsers that only support the ES5 version of JavaScript. The correct bundle will be loaded automatically by the browser, thanks to the support of ES6 modules in newer browsers.

This new feature results in the most significant single performance improvement for Angular v8. More modern browsers will be able to load less code and load a much smaller amount of polyfills.

Finally, Angular 8 Updates And Summary of New Features article is over.

The post Angular 8 Updates And Summary of New Features appeared first on AppDividend.

]]>
https://appdividend.com/2019/05/31/angular-8-updates-and-summary-of-new-features/feed/ 0