Home JavaScript

Node.js & Angular CRUD Tutorial – Step By Step Guide!


Previously, we learned how to create, read, update and delete database records with our AngularJS CRUD Tutorial. Today we will learn how to code CRUD with Angular 2.

Contents of this post include:

1.0 Prerequisite
2.0 Tutorial Overview
3.0 Output Preview6.
4.0 Setup The REST API

5.0 Angular Development Environment
5.1 Node.js
5.2 Node Package Manager (NPM)
5.3 Angular CLI
5.4 Angular Project

6.0 How To Read Records in Angular?
6.1 Generate “Read Products” Component
6.2 “Read Products” HTML Template
6.3 Create “Product” Service
6.4 Create Product Class
6.5 “Read Products” Component
6.6 AppComponent HTML Template
6.7 The App Component
6.8 Add Custom CSS
6.9 Output

7.0 How To Create or Insert Record in Angular?
7.1 Generate “Create Product” Component
7.2 “Create Product” HTML Template
7.3 The CreateProductComponent
7.4 Generate Category Service
7.5 Generate Category Class
7.6 Add createProduct() method in ProductService
7.7 Add ReactiveFormsModule
7.8 Change ReadProductsComponent
7.9 Change AppComponent HTML Template
7.10 Change AppComponent
7.11 Output

8.0 How To Read One Record in Angular?
8.1 Generate “Read One Product” Component
8.2 “Read One Product” HTML Template
8.3 Change ReadOneProductComponent
8.4 Add readOneProduct() method in Product Service
8.5 Change AppComponent HTML Template
8.6 Change AppComponent
8.7 Change ReadProductsComponent
8.8 Output

9.0 How To Update Record in Angular?
9.1 Generate “Update Product” Component
9.2 Build “Update Product” HTML Template
9.3 The UpdateProductComponent
9.4 Add updateProduct() method in ProductService
9.5 Change ReadProductsComponent
9.6 Change AppComponent HTML Template
9.7 Change AppComponent
9.8 Output

10.0 How To Delete Record in Angular?
10.1 Generate “Delete Product” Component
10.2 Build “Delete Product” HTML Template
10.3 The DeleteProductComponent
10.4 Add deleteProduct() method in ProductService
10.5 Change ReadProductsComponent
10.6 Change AppComponent HTML Template
10.7 Change AppComponent
10.8 Output

11.0 How To Run The Source Code?
12.0 Download LEVEL 1 Source Code
13.0 Download LEVEL 2 Source Code
14.0 Download ALL LEVELS

15.0 What’s Next?
16.0 Related Tutorials
17.0 Notes

Before we start, we want to let you know that your feedback is important to us!

If there's a section in this tutorial that is confusing or hard to understand, we consider it as a problem. Please let us know. We will solve this problem within 24 hours.

Send a detailed description of the problem to my email to mike@codeofaninja.com today. Use "codeofaninja.com improvement" as the subject of your email. Thank you!

1.0 Prerequisite

You must have some coding knowledge and experience with HTML, CSS and JavaScript because we will deal mostly with the client side of the web. PHP & MySQL or MariaDB for the REST API. And of course, Coffee (optional).

Angular is a framework for developing large JavaScript applications. It is used for building SPAs or Single-Page Applications.

Aside from the above definition, I require you to have at least a basic understanding of the following topics.

You don’t have to learn coding yet. For now, just understand what they are, why use them and who uses them. The links above should be helpful for you.

For additional learning about the topics above, you can always do your own Google search as well.

2.0 Tutorial Overview

If these platforms, frameworks, language and concepts are new to you, please do not get overwhelmed. Take one step at a time.

I’m going to show you exactly what you should learn next. You can ask me using the comments section below as well.

The key to learning here is to follow our tutorial, study, practice and ASK for help IF you really can’t understand something after you did your research.

You don’t have to learn all of it in one day. Downloading our source codes is your huge advantage as well.

In this post, we are going to learn how to coding using the following tools.

  • Angular / Angular2 – a development platform for building mobile and desktop web applications. Read more about this on section 2.0 of this post.
  • TypeScript – a superset of JavaScript. It is developed and maintained by Microsoft. For this tutorial, TypeScript will allow us to use classes in JavaScript.
  • Node.js – For this tutorial, this will allow us to run our app anywhere on our machine and install open source libraries easily.
  • REST API – To learn how to build a REST API using PHP & MySQL, see section 4.0 below. REST uses HTTP for all four CRUD (Create/Read/Update/Delete) operations.
  • Bootstrap – is in charge of making our app’s user interface look better.

I’m very excited to show you how to use the tools I mentioned above. Please continue below.

3.0 Output Preview

At the end of this tutorial, we will achieve the following output.

3.1 LEVEL 1 Source Code Output


3.2 LEVEL 2 Source Code Output


The LEVEL 2 source code output proves that you can add and customize more features. It’s easier and faster if you will learn by following our tutorial below.

Downloading our source codes is your huge advantage as well. For now, let’s proceed to the step by step tutorial of our LEVEL 1 source code. Enjoy!

4.0 Setup The REST API

In this tutorial, we are going to use a REST API built with PHP.

We did not include REST API source code because we want you to focus on learning how to code with Angular 2, not PHP.

But the good news is, we made a separate tutorial about how to build a simple REST API with PHP. Click here to learn the step-by-step PHP REST API tutorial.

I highly recommend learning our REST API tutorial first. This is because we are going to use that API for the rest of this tutorial.

But if you already have your own REST API that will work with this tutorial, that’s okay as well.

In my case, one example where I can access the REST API is: http://localhost/api/product/read.php

That link will show me the list of products from the database, in JSON format. It looks like the following screenshot.

The data above will be consumed by our Angular app. The list of products will be displayed in Bootstrap table with buttons like “Read One”, “Update” and “Delete”. You will see it in the “How To Read Records in Angular?” section of this tutorial.

By the way, I’m using a Chrome extension called JSONView to make the JSON data readable in the browser.

5.0 Angular Development Environment

First, we will set up the Angular development environment.

5.1 Node.js

1. Download & Install Node.js

  • Go to Node.js website and download the Node.js installer.
  • Run the installer and follow the installation process.

2. Open Your Command Prompt or Command Line. I’m using Windows, so I have:

3. Check Node.js Version by typing the following in the command prompt and pressing ‘Enter’ on the keyboard.

node --version 

If you’re using using Mac, I think you should always add ‘sudo’, so it will look like.

sudo node --version 

4. Update Node.js if your version is older than what’s on the Node.js homepage.

5.2 Node Package Manager (NPM)

1. How to Install NPM? NPM is bundled with node so you don’t have to do this.

2. Check NPM Version by typing the following in your command line.

npm --version

3. Update NPM because it gets updated more frequently than Node does, so you’ll want to make sure it’s the latest version.

If you’re version is older than what is in the NPM change log, update NPM using the following command.

npm install npm@latest -g

5.3 Angular CLI

1. Install Angular CLI, it usually takes several minutes. Type the following in your command line.

npm install -g angular-cli 

2. Check Angular CLI Version by typing the following in your command line.

ng --version 

3. Update Angular CLI if your version is older than what is in the Angular CLI change log.

This part assumes that you already created your project with Angular CLI. So, go to your project directory first. For example:

cd c:\users\ninjazhai\angular-crud-level-one

To update Angular CLI, you must update both the global package and your project’s local package.

Global package:

npm uninstall -g angular-cli @angular/cli
npm cache clean
npm install -g @angular/cli@latest

Local project package:

rm -rf node_modules dist # use rmdir on Windows
npm install --save-dev @angular/cli@latest
npm install
ng update

5.4 Angular Project

1. Create new Angular project with Angular CLI. This might take several minutes because it will create and install several files and packages.

Type the following in your command line and press enter.

ng new angular-crud-level-one

If you’re working on a LEVEL 2 source code, type the following instead.

ng new angular-crud-level-two

2. Go to your Angular project directory

cd angular-crud-level-one

3. Your command line should look like the following.

4. Run your project using “ng serve” in the command line. It will look like the following.

5. View the project in your browser. Use the following URL: http://localhost:4200/

6. If you will go to your project directory, in my case, its “C:\Users\ninjazhai\angular-crud-level-one” you will see the files and folders that looks like the following.

You don’t have to open or read each files and folders above because they are auto-generated by the Angular CLI. What you have to focus on are the steps we are taking in this tutorial.

7. To make our CRUD app look good, we are going to use Bootstrap. So, open “src” folder. Open “index.html” file and put the following Bootstrap CSS file before the closing “head” tag.

<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">

You can install Bootstrap via npm, but I prefer the method above.

8. Let’s verify if Bootstrap is working. Add a bootstrap button on page. Open “src” folder. Open “app” folder. Open “app.component.html” file. Put the following code.

<button class='btn btn-success'>click me</button>

9. Save the file. See your browser. The URL http://localhost:4200 is automatically reloaded. You should see something like the following.

6.0 How To Read Records in Angular?

Before we start with the coding, I need to give you some important pointers to have more success in following this tutorial.

In the next sections, I will put helpful links for you to have deeper understanding about the “modules” or “imports” we are using. I will place some helpful tips as well.

So, let’s start coding!

Using Angular 2, let’s start by reading records from the REST API. We will display the data on an HTML table.

6.1 Generate “Read Products” Component

Open another command prompt. Type the following and press enter.

ng g component read-products

To explain the above command:

  • ng – Angular CLI
  • g – generate
  • component – angular component
  • read-products – name of the component

It will generate the following folder and files inside the “app” folder.

├─ read-products/
├─── read-products.component.css
├─── read-products.component.html
├─── read-products.component.spec.ts
├─── read-products.component.ts

Learn more about what is an Angular component here.

TIP: If you need a component to be inside a parent component, you can type a command that looks like the following.

ng g component products/read-products

To explain the “products/read-products” above, “products” is the parent component, and “read-products” is the child component.

Here are some more examples. See the commands pointed by the arrows below.

6.2 “Read Products” HTML Template

On our “read products” page, we will have a “create product” button and HTML table that will hold our list of products from the API.

The HTML table will hold the “Read One”, “Update” and “Delete” buttons as well.

Under “/app/read-products” folder, open “read-products.component.html” file. Remove its current content and put the following code.

<div class="row m-b-18px">
    <div class="col-md-12">
        <!-- button to create new product -->
        <a (click)="createProduct()" class='btn btn-primary pull-right'>
        	<span class='glyphicon glyphicon-plus'></span> Create Product
        </a>
    </div>
</div>

<div class="row">
    <div class="col-md-12">

        <!-- HTML table for our list of product records -->
        <table class='table table-hover table-responsive table-bordered'>

            <tr>
                <th>Product</th>
                <th>Price</th>
                <th>Description</th>
                <th>Category</th>
                <th>Actions</th>
            </tr>

            <!-- Use *ngFor directive to loop throught our list of products. -->
            <tr *ngFor="let product of products">
                <td>{{product.name}}</td>
                <td>{{product.price}}</td>
                <td>{{product.description}}</td>
                <td>{{product.category_name}}</td>
                <td>
                    <!-- read one product button -->
                    <a (click)="readOneProduct(product.id)" class='btn btn-primary m-r-5px'>
                        <span class='glyphicon glyphicon-eye-open'></span> Read
                    </a>

                    <!-- edit product button -->
                    <a (click)="updateProduct(product.id)" class='btn btn-info m-r-5px'>
                        <span class='glyphicon glyphicon-edit'></span> Edit
                    </a>

                    <!-- delete product button -->
                    <a (click)="deleteProduct(product.id)" class='btn btn-danger m-r-5px'>
                        <span class='glyphicon glyphicon-remove'></span> Delete
                    </a>
                </td>
            </tr>
        </table>
    </div>
</div>

To explain some of the code above:

(click)="createProduct()"

The above code means that when the element that holds this attribute (a button or a link) was “clicked”, the createProduct() method in the component will be triggered.

This attribute is called event binding. Learn more about Angular event binding here.

<tr *ngFor="let product of products">

The above code is the “for loop” in Angular. Our code loops through the list of products from the API so that each record can be displayed as a table row.

The “*ngFor” is called a directive. It changed the appearance and behavior of our HTML table. Learn more about Angular Directives here.

6.3 Create “Product” Service

The “product” service is where we will put the code that allows as to contact the remote server or API. In this case, we are going to get the list for products.

Use the following in the command line to generate the “product” service.

ng g service product

You will see a new file inside the “app” folder. The file name is “product.service.ts”, open that file and put the following code.

import { Injectable } from '@angular/core';
import { Http, Response, Headers, RequestOptions } from '@angular/http';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/catch';
import { Product } from './product';

@Injectable()

// Service for products data.
export class ProductService {

    // We need Http to talk to a remote server.
    constructor(private _http : Http){ }

    // Get list of products from remote server.
    readProducts(): Observable<Product[]>{
        return this._http
            .get("http://localhost/api/product/read.php")
            .map(res => res.json());
    }

}

Our code above is an example of a Service. A service can be used by many components. You can think of it as a way to manage our data calls. Learn more about Angular Services here.

Our Services returns Observables. In this tutorial, we use Observables to handle multiple values. Learn more about Angular Observables here.

We used the HTTP Client as well to talk to a remote server. Learn more about Angular HTTP client here.

6.4 Create Product Class

The previous section’s code will not work without the “product” class. This is because we imported it as seen in the “imports” section.

We need the product class for the “create” and “update” features later. So, let’s create the “product” class using Angular CLI. Use the following command in your command line.

ng g class product

The above command will generate a new file under the “app” folder. The file name is “product.ts”, open that file and put the following code.

// Product class to define this object's properties.
export class Product {
    constructor(
        public id: number,
        public name: string,
        public price: number,
        public description: string,
        public category_id: number,
        public category_name: string
    ){}
}

6.5 “Read Products” Component

Under the “app” folder, open “read-products.component.ts”. Change the code to the following.

import { Component, OnInit, Input, Output, EventEmitter } from '@angular/core';
import { ProductService } from '../product.service';
import { Observable } from 'rxjs/Observable';
import { Product } from '../product';

@Component({
    selector: 'app-read-products',
    templateUrl: './read-products.component.html',
    styleUrls: ['./read-products.component.css'],
    providers: [ProductService]
})

export class ReadProductsComponent implements OnInit {

    // store list of products
    products: Product[];

    // initialize productService to retrieve list products in the ngOnInit()
    constructor(private productService: ProductService){}

    // methods that we will use later
    createProduct(){}
    readOneProduct(id){}
    updateProduct(id){}
    deleteProduct(id){}

    // Read products from API.
    ngOnInit(){
        this.productService.readProducts()
            .subscribe(products =>
                this.products=products['records']
            );
    }
}

6.6 AppComponent HTML Template

You can think of this as the “parent” HTML template because it will be the wrapper for smaller component which include the “ReadProductsComponent” and other component we will work on later.

Under the “app” folder, open “app.component.html” and change the code to the following.

<!-- container -->
<div class="container">

    <!-- show page header -->
    <div class="row">
        <div class="col-md-12">
            <div class='page-header'><h1>{{title}}</h1></div>
        </div>
    </div>

    <!-- Show this view if "show_read_products_html" property of AppComponent is true. -->
    <app-read-products
        *ngIf="show_read_products_html">
    </app-read-products>

</div>
<!-- /container -->

6.7 The App Component

In this tutorial, the “AppComponent” is the “parent” component of all our component. You can think of it as the “consumer” of our sub components like “ReadProductsComponent”.

Under the “app” folder, open “app.component.ts” file and change the code to the following.

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

@Component({
    selector: 'app-root',
    templateUrl: './app.component.html',
    styleUrls: ['./app.component.css']
})

export class AppComponent {
    // properties for child components
    title="Read Products";
    product_id;

    // properties used to identify what views to show
    show_read_products_html=true;
}

6.8 Add Custom CSS

We are going to fix some UI spacing using custom CSS. Under the “src” folder, open styles.css file and put the following CSS code.

/* You can add global styles to this file, and also import other style files */
.m-b-18px{ margin-bottom: 18px; }
.m-r-5px{ margin-right: 5px; }
.w-40-pct{ width: 40%; }
.text-align-center{ text-align: center; }

6.9 Output

After doing all the steps above, the output will look like the following.

7.0 How To Create or Insert Record in Angular?

7.1 Generate “Create Product” Component

Use the following command in the commmand line.

ng g component create-product

It will generate the following folder and files inside the “app” folder.

├─ create-product/
├─── create-product.component.css
├─── create-product.component.html
├─── create-product.component.spec.ts
├─── create-product.component.ts

7.2 “Create Product” HTML Template

We will build the HTML form where the user can enter product information. This HTML form contains:

  • Product input fields – name, price, description, category
  • Category drop-down list
  • Submit button – disabled if form is invalid
  • Validation messages as well – if not error message, submit button will be enabled
  • The “Read Products” button is used to go back to product list view.

Under “/app/create-product/” folder, open create-product.component.html and change the code to the following.

<div class="row m-b-18px">
	<div class="col-md-12">
		<a (click)="readProducts()" class='btn btn-primary pull-right'>
			<span class='glyphicon glyphicon-list'></span> Read Products
		</a>
	</div>
</div>

<!-- HTML form for creating a product -->
<div class="row">
<div class="col-md-12">

<!--
	1. Bind our HTML form to Angular using [formGroup]
	2. If form was submitted, call createProduct() method of CreateProductComponent
-->
<form [formGroup]="create_product_form" (ngSubmit)="createProduct()">
<table class="table table-hover table-responsive table-bordered">
	<tr>
		<td>Name</td>
		<td>
			<!-- Bind this input field to our 'angular form field' using formControlName -->
			<input
				formControlName="name"
				name="name" type="text"
				class="form-control" required />

			<!-- show this error if the field is 'empty' and 'touched' -->
			<div
				*ngIf="create_product_form.get('name').touched && create_product_form.get('name').hasError('required')"
				class="alert alert-danger">
				Name is required.
			</div>
		</td>
	</tr>

	<tr>
		<td>Price</td>
		<td>
			<input
				formControlName="price"
				type="number" name="price"
				class="form-control" required />

			<!-- show this error if the field is 'empty' and 'touched' -->
			<div
				*ngIf="create_product_form.get('price').touched && create_product_form.get('price').hasError('required')"
				class="alert alert-danger">
			Price is required.
			</div>
		</td>
	</tr>

	<tr>
		<td>Description</td>
		<td>
			<textarea
				formControlName="description"
				name="description" class="form-control" required></textarea>

				<!-- show this error if the field is 'empty' and 'touched' -->
				<div
					*ngIf="create_product_form.get('description').touched && create_product_form.get('description').hasError('required')"
					class="alert alert-danger">
					Description is required.
				</div>
		</td>
	</tr>

	<tr>
		<td>Category</td>
		<td>
			<select formControlName="category_id" name="category_id" class="form-control">
				<option *ngFor="let category of categories" value="{{category.id}}">
					{{category.name}}
				</option>
			</select>
			<!-- show this error if the field is 'empty' and 'touched' -->
			<div
				*ngIf="create_product_form.get('category_id').touched && create_product_form.get('category_id').hasError('required')"
				class="alert alert-danger">
				Category is required.
			</div>
		</td>
	</tr>

	<tr>
		<td></td>
		<td>
			<!-- disable the submit button if the form is 'invalid' -->
			<button class="btn btn-primary" type="submit" [disabled]="create_product_form.invalid">
				<span class="glyphicon glyphicon-plus"></span> Create
			</button>
		</td>
	</tr>
</table>
</form>

</div>
</div>

7.3 The CreateProductComponent

This component is coded based on what our HTML template contains. As you can see, this CreateProductComponent have the:

  • Angular form builder based on the HTML form fields.
  • CategoryService to read list of categories from the API to fill out the category drop-down. We will create this service later.
  • Category class because we are using the CategoryService.
  • ProductService to send form data to the API.
  • EventEmitter to go back to product list view.

Please read the code comments below to understand more of it. I will provide helpful links after the code as well.

import { Component, Input, Output, EventEmitter } from '@angular/core';
import { FormGroup, FormControl, Validators, FormBuilder } from '@angular/forms';
import { ProductService } from '../product.service';
import { CategoryService } from '../category.service';
import { Observable } from 'rxjs/Observable';
import { Product } from '../product';
import { Category } from '../category';

@Component({
    selector: 'app-create-product',
    templateUrl: './create-product.component.html',
    styleUrls: ['./create-product.component.css'],
    providers: [ProductService, CategoryService]
})

// component for creating a product record
export class CreateProductComponent {

    // our angular form
    create_product_form: FormGroup;

    // @Output will tell the parent component (AppComponent) that an event happened in this component
    @Output() show_read_products_event = new EventEmitter();

    // list of categories
    categories: Category[];

    // initialize 'product service', 'category service' and 'form builder'
    constructor(
        private productService: ProductService,
        private categoryService: CategoryService,
        formBuilder: FormBuilder
    ){
        // based on our html form, build our angular form
        this.create_product_form = formBuilder.group({
            name: ["", Validators.required],
            price: ["", Validators.required],
            description: ["", Validators.required],
            category_id: ["", Validators.required]
        });
    }

    // user clicks 'create' button
    createProduct(){

        // send data to server
        this.productService.createProduct(this.create_product_form.value)
            .subscribe(
                 product => {
                    // show an alert to tell the user if product was created or not
                    console.log(product);

                    // go back to list of products
                    this.readProducts();
                 },
                 error => console.log(error)
             );
    }

    // user clicks the 'read products' button
    readProducts(){
        this.show_read_products_event.emit({ title: "Read Products" });
    }

    // what to do when this component were initialized
    ngOnInit(){
        // read categories from database
        this.categoryService.readCategories()
            .subscribe(categories => this.categories=categories['records']);
    }
}

7.4 Generate Category Service

Use the following in the command line.

ng g service category

It will generate a file under the “app” folder. The file name is “category.service.ts”, open that file and put the following code.

import { Injectable } from '@angular/core';
import { Http, Response } from '@angular/http';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/catch';
import { Category } from './category';

@Injectable()

// Service for categories data.
export class CategoryService {

    // We need Http to talk to a remote server.
    constructor(private _http: Http) { }

    // Get list of categories from database via api.
    readCategories(): Observable<Category[]>{
        return this._http
            .get("http://localhost/api/category/read.php")
            .map(res => res.json());
    }

}

7.5 Generate Category Class

Execute the following in the command line.

ng g class category

It will create a file under the “app” folder. The file name is “category.ts”, open that file and put the following code.

// Category class to define this object's properties.
export class Category {
    id: number;
    name: string;
    description: string;
}

7.6 Add createProduct() method in ProductService

Under the “app” folder, open “product.service.ts” file and put the following code after the readProducts() method.

// Send product data to remote server to create it.
createProduct(product): Observable<Product>{

    let headers = new Headers({ 'Content-Type': 'application/json' });
    let options = new RequestOptions({ headers: headers });

    return this._http.post(
        "http://localhost/api/product/create.php",
        product,
        options
    ).map(res => res.json());
}

7.7 Add ReactiveFormsModule

ReactiveFormsModule is needed for our Angular form to work. Under the “app” folder, open “app.module.ts” and find this line:

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

and change it to this:

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

Add it in the “imports” as well, so find:

imports: [
    BrowserModule,
    FormsModule,
    HttpModule
],

and change it to this:

imports: [
    BrowserModule,
    FormsModule,
    HttpModule,
    ReactiveFormsModule
],

To learn more about ReactiveFormsModule, click here and here.

7.8 Change ReadProductsComponent

The “Create Product” form must be show when the “Create Product” button (located in ReadProductsComponent) was clicked.

Under “/app/read-products” folder, open “read-products.component.ts” file. Add the following output property before the “products” property.

/*
    * Needed to notify the 'consumer of this component', which is the 'AppComponent',
      that an 'event' happened in this component.
*/
@Output() show_create_product_event=new EventEmitter();

still in read-products.component.ts, find:

createProduct(){}

and change it to:

// when user clicks the 'create' button
createProduct(){
    // tell the parent component (AppComponent)
    this.show_create_product_event.emit({
        title: "Create Product"
    });
}

7.9 Change AppComponent HTML Template

Under “app” folder, open “app.component.html” and find:

<app-read-products
    *ngIf="show_read_products_html">

and change it to:

<app-read-products
    *ngIf="show_read_products_html"
    (show_create_product_event)="showCreateProduct($event)">

The “app-create-product” tag is the “selector” of our “CreateProductComponent”, so this tag will render our “Create Product” HTML form. Add the following code in “app.component.html” as well.

<!--
    * Show this view if "show_create_product_html" is true.

    * If (show_read_products_event) was emitted in CreateProductComponent,
      trigger showReadProducts() method in AppComponent.
-->
<app-create-product
    *ngIf="show_create_product_html"
    (show_read_products_event)="showReadProducts($event)">
</app-create-product>

7.10 Change AppComponent

We will change the AppComponent by adding the properties and methods required by the HTML template on the previous section.

Under “app” folder, open “app.component.html” file and find:

show_read_products_html=true;

and add the following properties after it:

show_create_product_html=false;
show_read_one_product_html=false;
show_update_product_html=false;
show_delete_product_html=false;

Add the following methods as well.

// show the 'create product form'
showCreateProduct($event){

    // set title
    this.title=$event.title;

    // hide all html then show only one html
    this.hideAll_Html();
    this.show_create_product_html=true;
}

// show products list
showReadProducts($event){
    // set title
    this.title=$event.title;

    // hide all html then show only one html
    this.hideAll_Html();
    this.show_read_products_html=true;
}

// hide all html views
hideAll_Html(){
    this.show_read_products_html=false;
    this.show_read_one_product_html=false;
    this.show_create_product_html=false;
    this.show_update_product_html=false;
    this.show_delete_product_html=false;
}

7.11 Output

The output of doing this section should look like the following.

8.0 How To Read One Record in Angular?

8.1 Generate “Read One Product” Component

Use the following in the commmand line.

ng g component create-product

It will generate the following folder and files inside the “app” folder.

├─ read-one-product/
├─── read-one-product.component.css
├─── read-one-product.component.html
├─── read-one-product.component.spec.ts
├─── read-one-product.component.ts

8.2 “Read One Product” HTML Template

When a user clicks on the “Read One” button, our app will show a product information in HTML table.

Under “/app/read-one-product/” folder, open read-one-product.component.html and change the code to the following.

<div class="row m-b-18px">
	<div class="col-md-12">
		<a (click)="readProducts()" class='btn btn-primary pull-right'>
			<span class='glyphicon glyphicon-list'></span> Read Products
		</a>
	</div>
</div>

<div class="row">
	<div class="col-md-12">
		<!-- HTML table for displaying a product details -->
		<table class='table table-hover table-responsive table-bordered'>

			<tr>
				<td class="w-40-pct">Name</td>
				<td>{{product?.name}}</td>
			</tr>

			<tr>
				<td>Price</td>
				<td>&#36;{{product?.price}}</td>
			</tr>

			<tr>
				<td>Description</td>
				<td>{{product?.description}}</td>
			</tr>

			<tr>
				<td>Category</td>
				<td>{{product?.category_name}}</td>
			</tr>

		</table>
	</div>
</div>

8.3 Change ReadOneProductComponent

Under “/app/read-one-product/” folder, open “read-one-product.component.ts” file. Change the code to the following.

import { Component, OnInit, Input, Output, OnChanges, EventEmitter } from '@angular/core';
import { ProductService } from '../product.service';
import { Observable } from 'rxjs/Observable';
import { Product } from '../product';

@Component({
    selector: 'app-read-one-product',
    templateUrl: './read-one-product.component.html',
    styleUrls: ['./read-one-product.component.css'],
    providers: [ProductService]
})

export class ReadOneProductComponent implements OnChanges {

    /*
        @Output will tell the parent component (AppComponent)
        that an event has happened (via .emit(), see readProducts() method below)
    */
    @Output() show_read_products_event = new EventEmitter();

    // @Input means it will accept value from parent component (AppComponent)
    @Input() product_id;

    product: Product;

    // initialize product service
    constructor(private productService: ProductService){}

    // user clicks the 'read products' button
    readProducts(){
        this.show_read_products_event.emit({ title: "Read Products" });
    }

    // call the record when 'product_id' was changed
    ngOnChanges(){
        this.productService.readOneProduct(this.product_id)
            .subscribe(product => this.product=product);
    }

}

8.4 Add readOneProduct() method in Product Service

Under the “app” folder, open “product.service.ts” file and put the following code after the createProduct() method.

// Get a product details from remote server.
readOneProduct(product_id): Observable<Product>{
    return this._http
        .get("http://localhost/api/product/read_one.php?id="+product_id)
        .map(res => res.json());
}

8.5 Change AppComponent HTML Template

Open app.component.html file and find:

<app-read-products
    *ngIf="show_read_products_html"
    (show_create_product_event)="showCreateProduct($event)">

and change it to:

<app-read-products
    *ngIf="show_read_products_html"
    (show_create_product_event)="showCreateProduct($event)"
    (show_read_one_product_event)="showReadOneProduct($event)">

The “app-read-one-product” tag is the “selector” of our “ReadOneProductComponent”. This tag will render our “Read One Product” HTML table with the product data.

Add the following code in “app.component.html” as well.

<!--
    * Show this view if "show_read_one_product_html" is true.

    * If (show_read_products_event) was emmited in ReadOneProductComponent,
      trigger showReadProducts() method in AppComponent.

    * Pass "product_id" property value of AppComponent
      to [product_id] property of ReadOneProductComponent.
-->
<app-read-one-product
    *ngIf="show_read_one_product_html"
    (show_read_products_event)="showReadProducts($event)"
    [product_id]="product_id">
</app-read-one-product>

8.6 Change AppComponent

Open “app.component.html” file and add the following property under “title” property.

product_id;

add the following method.

// show details of a product
showReadOneProduct($event){

    // set title and product ID
    this.title=$event.title;
    this.product_id=$event.product_id;

    // hide all html then show only one html
    this.hideAll_Html();
    this.show_read_one_product_html=true;
}

8.7 Change ReadProductsComponent

Under “/app/read-products/” folder, open read-products.component.ts file and find:

@Output() show_create_product_event=new EventEmitter();

…then add the following properties below it.

@Output() show_read_one_product_event=new EventEmitter();
@Output() show_update_product_event=new EventEmitter();
@Output() show_delete_product_event=new EventEmitter();

Still in “read-products.component.ts” file, find:

readOneProduct(id){}

…then change it to:

// when user clicks the 'read' button
readOneProduct(id){
    console.log('rp comp readOneProduct');
    // tell the parent component (AppComponent)
    this.show_read_one_product_event.emit({
        product_id: id,
        title: "Read One Product"
    });
}

8.8 Output

When you click the “Read One” button, you should see something like the following.

9.0 How To Update Record in Angular?

9.1 Generate “Update Product” Component

Use the following in the commmand line.

ng g component update-product

It will generate the following folder and files inside the “app” folder.

├─ update-product/
├─── update-product.component.css
├─── update-product.component.html
├─── update-product.component.spec.ts
├─── update-product.component.ts

9.2 Build “Update Product” HTML Template

We will build the HTML form where the user can update product information. This HTML form contains:

  • Product input fields – name, price, description, category
  • Category drop-down list
  • Submit button – disabled if form is invalid
  • Validation messages – if no error message, submit button will be enabled
  • The “Read Products” button is used to go back to product list view.

Under “/app/update-product/” folder, open “update-product.component.html” file and change the code to the following.

<div class="row m-b-18px">
	<div class="col-md-12">
		<a (click)="readProducts()" class='btn btn-primary pull-right'>
			<span class='glyphicon glyphicon-list'></span> Read Products
		</a>
	</div>
</div>

<div class="row">
<div class="col-md-12">

<!-- HTML form for creating a product -->
<form [formGroup]="update_product_form" (ngSubmit)="updateProduct()">
<table class='table table-hover table-responsive table-bordered'>

	<tr>
		<td>Name</td>
		<td>
			<input formControlName="name"
				type='text' name='name'
				class='form-control' required />

			<!-- show this error if the field is 'touched' and 'empty' -->
			<div
				*ngIf="update_product_form.get('name').touched && update_product_form.get('name').hasError('required')"
				class="alert alert-danger">
				Name is required.
			</div>
		</td>
	</tr>

	<tr>
		<td>Price</td>
		<td>
			<input
				formControlName="price"
				type='number' name='price'
				class='form-control' required />

			<!-- show this error if the field is 'touched' and 'empty' -->
			<div
				*ngIf="update_product_form.get('price').touched && update_product_form.get('price').hasError('required')"
				class="alert alert-danger">
			Price is required.
			</div>
		</td>
	</tr>

	<tr>
		<td>Description</td>
		<td>
			<textarea
				formControlName="description"
				name='description' class='form-control'></textarea>

			<!-- show this error if the field is 'touched' and 'empty' -->
			<div
				*ngIf="update_product_form.get('description').touched && update_product_form.get('description').hasError('required')"
				class="alert alert-danger">
			Description is required.
			</div>
		</td>
	</tr>

	<tr>
		<td>Category</td>
		<td>
			<select formControlName="category_id" name='category_id' class='form-control'>
				<option
					*ngFor="let category of categories"
					[selected]="category_id==category.id"
					value='{{category.id}}'>
					{{category.name}}
				</option>
			</select>

			<!-- show this error if the field is 'touched' and 'empty' -->
			<div
				*ngIf="update_product_form.get('category_id').touched && update_product_form.get('category_id').hasError('required')"
				class="alert alert-danger">
				Category is required.
			</div>
		</td>
	</tr>

	<tr>
		<td></td>
		<td>
			<!-- Submit buttons is [disabled] if form is invalid. -->
			<button class="btn btn-primary" type="submit" [disabled]="update_product_form.invalid">
				<span class="glyphicon glyphicon-edit"></span> Update
			</button>
		</td>
	</tr>

</table>
</form>

</div>
</div>

9.3 The UpdateProductComponent

This component is coded based on our HTML template above. As you will see, this UpdateProductComponent have the:

  • Angular form builder based on the HTML form fields.
  • CategoryService to read list of categories from the API to fill out the category drop-down.
  • Category class because we are using the CategoryService.
  • ProductService to send form data to the API.
  • EventEmitter to go back to product list view.
import { Component, OnChanges, Input, Output, EventEmitter } from '@angular/core';
import { FormGroup, FormControl, Validators, FormBuilder } from '@angular/forms';
import { ProductService } from '../product.service';
import { CategoryService } from '../category.service';
import { Observable } from 'rxjs/Observable';
import { Category } from '../category';

@Component({
    selector: 'app-update-product',
    templateUrl: './update-product.component.html',
    styleUrls: ['./update-product.component.css'],
    providers: [ProductService, CategoryService]
})
export class UpdateProductComponent implements OnChanges {

    // our angular form
    update_product_form: FormGroup;

    @Output() show_read_products_event = new EventEmitter();
    @Input() product_id;

    categories: Category[];

    // initialize product & category services
    constructor(
        private productService: ProductService,
        private categoryService: CategoryService,
        private formBuilder: FormBuilder
    ){

        // build angular form
        this.update_product_form = this.formBuilder.group({
            name: ["", Validators.required],
            price: ["", Validators.required],
            description: ["", Validators.required],
            category_id: ["", Validators.required]
        });
    }

    // user clicks 'create' button
    updateProduct(){

        // add product_id in the object so it can be updated
        this.update_product_form.value.id = this.product_id;

        // send data to server
        this.productService.updateProduct(this.update_product_form.value)
            .subscribe(
                 product => {
                    // go back to list of products
                    this.readProducts();
                 },
                 error => console.log(error)
             );
    }

    // user clicks the 'read products' button
    readProducts(){
        this.show_read_products_event.emit({ title: "Read Products" });
    }

    // call the record when 'product_id' was changed
    ngOnChanges(){

        // read one product record
        this.productService.readOneProduct(this.product_id)
            .subscribe(product => {

                // put values in the form
                this.update_product_form.patchValue({
                    name: product.name,
                    price: product.price,
                    description: product.description,
                    category_id: product.category_id
                });
            });
    }

    // read categories from database
    ngOnInit(){
        this.categoryService.readCategories()
            .subscribe(categories => this.categories=categories['records']);
    }
}

9.4 Add updateProduct() method in ProductService

Under “app” folder, open “product.service.ts” file and add the following code after “readOneProduct()” method. The updateProduct() will post updated product information to API.

// Send product data to remote server to update it.
updateProduct(product): Observable<Product>{

    let headers = new Headers({ 'Content-Type': 'application/json' });
    let options = new RequestOptions({ headers: headers });

    return this._http.post(
        "http://localhost/api/product/update.php",
        product,
        options
    ).map(res => res.json());
}

9.5 Change ReadProductsComponent

The “Update Product” form must be show when the “Update” button (located in ReadProductsComponent) was clicked.

Under “/app/read-products/” folder, open “read-products.component.ts” file and find:

updateProduct(id){}

…then change the code to:

// when user clicks the 'update' button
updateProduct(id){
    // tell the parent component (AppComponent)
    this.show_update_product_event.emit({
        product_id: id,
        title: "Update Product"
    });
}

9.6 Change AppComponent HTML Template

We have to tell the parent component (AppComponent) to show the “Update Product” form on the event of “Update Product” button click.

Under “app” folder, open “app.component.html” and find “app-read-products” tag and add the following as attribute.

(show_update_product_event)="showUpdateProduct($event)"

Next, the “app-update-product” tag is the “selector” of our “UpdateProductComponent”, so this tag will render our “Update Product” HTML form. Add the following code in “app.component.html” as well.

<!--
    * Show this view if "show_update_product_html" is true.

    * Pass "product_id" property value of AppComponent
      to [product_id] property of UpdateProductComponent.

    * If (show_read_products_event) was emitted in UpdateProductComponent,
      trigger showReadProducts() method in AppComponent.
-->
<app-update-product
    *ngIf="show_update_product_html"
    [product_id]="product_id"
    (show_read_products_event)="showReadProducts($event)">
</app-update-product>

9.7 Change AppComponent

We used showUpdateProduct($event) method in the previous section. We have to add it on our AppComponent. Under “app” folder, open “app.component.html” file and add the following code inside the class.

// show the 'update product form'
showUpdateProduct($event){

    // set title and product ID
    this.title=$event.title;
    this.product_id=$event.product_id;

    // hide all html then show only one html
    this.hideAll_Html();
    this.show_update_product_html=true;
}

9.8 Output

When you click the “Update” button, you should see something like the following.

10.0 How To Delete Record in Angular?

10.1 Generate “Delete Product” Component

Use the following in the commmand line.

ng g component delete-product

It will generate the following folder and files inside the “app” folder.

├─ delete-product/
├─── delete-product.component.css
├─── delete-product.component.html
├─── delete-product.component.spec.ts
├─── delete-product.component.ts

At this moment, your command prompt should look like the following.

10.2 Build “Delete Product” HTML Template

Our “Delete Product” HTML template will contain the “Are you sure?” message with “Yes” and “No” button.

Under “/app/delete-product/” folder, open “delete-product.component.html” and change the code to the following.

<div class="row">
    <div class="col-md-3"></div>

    <div class="col-md-6">
        <div class="panel panel-default">
            <div class="panel-body text-align-center">Are you sure?</div>
            <div class="panel-footer clearfix">
                <div class="text-align-center">

                    <!-- if 'Yes' button was clicked, delete the record and go back to records list -->
                    <button (click)="deleteProduct()" class="btn btn-danger m-r-5px">
                        <span class="glyphicon glyphicon-ok-sign"></span> Yes
                    </button>

                    <!-- if 'No' button was clicked, go back to records list -->
                    <button (click)="readProducts()" class="btn btn-primary">
                        <span class="glyphicon glyphicon-remove-sign"></span> No
                    </button>
                </div>
            </div>
        </div>
    </div>

    <div class="col-md-3"></div>
</div>

10.3 The DeleteProductComponent

When user click the “Yes” button, our app will send the product ID to the API for deletion. If the user click the “No” button, our app will show the list of products.

Under “/app/delete-product/” folder, open “delete-product.component.html” and change the code to the following.

import { Component, Input, Output, EventEmitter } from '@angular/core';
import { ProductService } from '../product.service';
import { Observable } from 'rxjs/Observable';
import { Product } from '../product';

@Component({
    selector: 'app-delete-product',
    templateUrl: './delete-product.component.html',
    styleUrls: ['./delete-product.component.css'],
    providers: [ProductService]
})

export class DeleteProductComponent {

    /*
        @Output will tell the parent component (AppComponent)
        that an event has happened (via .emit(), see readProducts() method below)
    */
    @Output() show_read_products_event = new EventEmitter();

    // @Input enable getting the product_id from parent component (AppComponent)
    @Input() product_id;

    // initialize product service
    constructor(private productService: ProductService){}

    // user clicks 'yes' button
    deleteProduct(){

        // delete data from database
        this.productService.deleteProduct(this.product_id)
            .subscribe(
                 product => {

                    // show an alert to tell the user if product was created or not
                    console.log(product);

                    // go back to list of products
                    this.readProducts();
                 },
                 error => console.log(error)
             );
    }

    // user clicks the 'read products' button
    readProducts(){
        this.show_read_products_event.emit({ title: "Read Products" });
    }

}

10.4 Add deleteProduct() method in ProductService

Using the “ProductService”, we are going to send an HTTP request to delete a product. A product record will be deleted based on given product_id parameter.

Under “app” folder, open “product.service.ts” file and add the following method inside the class.

// Send product ID to remote server to delete it.
deleteProduct(product_id){

    let headers = new Headers({ 'Content-Type': 'application/json' });
    let options = new RequestOptions({ headers: headers });

    return this._http.post(
        "http://localhost/api/product/delete.php",
        { id: product_id },
        options
    ).map(res => res.json());
}

10.5 Change ReadProductsComponent

The “Delete Product” prompt (Are you sure? delete confirmation message) must be shown when the “Delete” button (located in ReadProductsComponent) was clicked.

Under “/app/read-products/” folder, open “read-products.component.ts” file and find:

deleteProduct(id){}

…then change the code to:

// when user clicks the 'delete' button
deleteProduct(id){
    // tell the parent component (AppComponent)
    this.show_delete_product_event.emit({
        product_id: id,
        title: "Delete Product"
    });
}

10.6 Change AppComponent HTML Template

Under “app” folder, open “app.component.html” and find the “app-read-products” tag. Add the following attribute to it.

(show_delete_product_event)="showDeleteProduct($event)">

The “app-delete-product” tag is the “selector” of our “DeleteProductComponent”, so this tag will render our “Delete Product” confirmation prompt with “Yes” and “No” button. Add the following code in “app.component.html” as well.

<!--
    * Show this view if "show_delete_product_html" is true.

    * Pass "product_id" property value of AppComponent
      to [product_id] property of UpdateProductComponent.

    * If (show_read_products_event) was emitted in DeleteProductComponent,
      trigger showReadProducts() method in AppComponent.
-->
<app-delete-product
    *ngIf="show_delete_product_html"
    [product_id]="product_id"
    (show_read_products_event)="showReadProducts($event)">
</app-delete-product>

10.7 Change AppComponent

We used the showDeleteProduct($event) method on the previous section so we need to add it in our AppComponent.

Under “app” folder, open “app.component.ts” and add the following method inside the class.

// show 'are you sure?' prompt to confirm deletion of a record
showDeleteProduct($event){

    // set title and product ID
    this.title=$event.title;
    this.product_id=$event.product_id;

    // hide all html then show only one html
    this.hideAll_Html();
    this.show_delete_product_html=true;
}

10.8 Output

When you click the “Delete” button, you should see something like the following.

11.0 How To Run The Source Code?

We highly recommend for you to follow and study our well-detailed, step-by-step tutorial above first. Nothing beats experience when it comes to learning.

But we believe you will learn faster if you’ll see the final source code as well. We consider it as your additional guide.

Imagine the value or skill upgrade it can bring you. The additional income you can get from your work, projects or business. The precious time you save. Isn’t that what you want?

By now, you need to download our source codes. To do it, use any download buttons in the next few sections below.

Once you downloaded the source codes, here’s how you can run it.

  1. Extract the ZIP file you downloaded.
  2. Copy the “api” folder to root directory of your localhost.
  3. Setup the database using PhpMyAdmin. Import “api_db.sql” which is inside the “api” folder.
  4. Set up your Angular development environment. Follow section 5.0 above.
  5. Go to your development directory, open the “src” folder.
  6. Copy the “app” folder, “index.html” and “styles.css” file. Paste them to the “src” folder of your development directory
  7. Open your command prompt. Go to your project directory. Run: ng serve
  8. Open your browser and go to http://localhost:4200/

12.0 Download LEVEL 1 Source Code

FEATURES LEVEL 1
Create product YES
Read product YES
Read one product YES
Update product YES
Delete product YES
Bootstrap UI YES
PHP REST API source code YES
FREE email support for 3 months YES
Source code updates via email YES
Download Now

THANK YOU!

has been added to your cart!

Powered by Easy Digital Downloads

Thank you!

have been added to your cart!

Powered by Easy Digital Downloads

13.0 Download LEVEL 2 Source Code

FEATURES LEVEL 2
All features of LEVEL 1 YES
Create category YES
Read category YES
Read one category YES
Update category YES
Delete category YES
Navigation bar YES
FREE email support for 6 months YES
Download Now

THANK YOU!

has been added to your cart!

Powered by Easy Digital Downloads

Thank you!

have been added to your cart!

Powered by Easy Digital Downloads

14.0 Download ALL LEVELS

This means you will download the LEVEL 1 and 2 source codes in separate packages. Please select “ALL LEVELS” below and then click the “Download Now” button.

Download Now

THANK YOU!

has been added to your cart!

Powered by Easy Digital Downloads

Thank you!

have been added to your cart!

Powered by Easy Digital Downloads

Do you need more reasons to download it?

MORE REASONS TO DOWNLOAD THE CODE ALL
Use new skills for your multiple projects YES
Save huge amount of time learning Angular / Angular 2 YES
Code examples are direct to the point YES
Well explained and commented source code YES
Fast and friendly email support YES
Free source code updates YES

15.0 What’s Next?

We are currently building more high quality tutorials for PHP, Laravel, CakePHP, and Social Media APIs. We love publishing high-quality tutorials for you guys!

Please subscribe via email so that we can let you know immediately once these new and high-quality tutorials are published.

CLICK HERE TO SUBSCRIBE!

16.0 Related Tutorials

17.0 Notes

#1 Found An Issue?

If you found a problem with this code, we can solve it faster via Email or FB message, please send me a message via email mike@codeofaninja.com, or via our official Facebook page!

Please be more detailed about your issue. Best if you can provide an error message and your test or page URL. Thanks!

Please feel free to comment if you have any questions, suggestions, found something wrong or want to contribute to this code.

#2 Become a true Ninja!

We constantly add new tutorials and improve our existing tutorials and source codes. Be one of the first to know an update by subscribing to our FREE newsletter. Get a FREE EBOOK as well. CLICK HERE TO SUBSCRIBE FOR FREE!

#3 Thank You!

If you have a friend or know someone who needs this Angular CRUD Tutorial, please share this page to them! I know you will help them a lot by doing it. Thanks!