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 Preview
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

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";

    // 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

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

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

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!

Home JavaScript

React CRUD Tutorial – JavaScript Programming – Step By Step Guide!


Previously, we learned our jQuery AJAX CRUD tutorial. Today we will learn how to create or insert, read, update, and delete database records with React.

Our tutorial for today will cover the following contents:

1.0 Program Output
2.0 React: What, Why, Who and Think
3.0 Technologies Used In This Tutorial
4.0 Set Up The REST API

5.0 Basic Files & Folders
5.1 File Structure
5.2 Create index.html file
5.3 Create custom CSS file
5.4 Create main.component.js file
5.5 Create “products” scripts
5.5 Output

6.0 How To Read JSON Data Using React?
6.1 Create “Read Products” Component
6.2 Create “Top Actions” Component
6.3 Create “ProductsTable” component
6.4 Create “ProductRow” component
6.5 Output

7.0 How To Create or Insert Data Using React?
7.1 Create “CreateProductComponent” Class
7.2 Initialize component state
7.3 Handle form field changes
7.4 Handle “Save” button
7.5 Render “Create Product” HTML Form
7.6 Output

8.0 How To Read One Data Using React?
8.1 Create “ReadOneProductComponent” Class
8.2 Initialize component state
8.3 Render Component HTML
8.4 Output

9.0 How To Update Data Using React?
9.1 Create “UpdateProductComponent” Class
9.2 Initialize component state
9.3 Handle form field changes
9.4 Handle “Save Changes” button
9.5 Render “Update Product” HTML Form
9.6 Output

10.0 How To Delete Data Using React?
10.1 Create “DeleteProductComponent” Class
10.2 Change Page Title
10.3 Handle “Yes” Button
10.4 Render “Delete Confirmation” Box
10.5 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 Online Resources
18.0 Some Notes

1.0 Program Output

Below are some screenshots of our tutorial’s output. You can click an image to view the larger version of it. Use the left and right arrow to navigate through the screenshots.

1.1 LEVEL 1 Source Code Output


1.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!

2.0 React: What, Why, Who and Think

2.1 What is React?

React is a JavaScript library for building user interfaces. It is maintained by Facebook, Instagram and a community of individual developers and corporations.

2.2 Why use React?

Using React allows you to simply express how your app should look at any given point in time. React will automatically manage all UI updates when your underlying data changes. When the data changes, React conceptually hits the “refresh” button, and knows to only update the changed parts.

2.3 Who uses React?

Aside from Facebook and Instagram, many well-known companies uses React including: Dropbox, PayPal, Nextflix, Khan Academy, Airbnb, Alipay, Asana and many more.

2.4 Thinking in React

It is very important that we understand the thought process of building web apps with React. Here’s a start: We start with a mock. Then, we break the UI into a component or parts of the UI. In the following image, you can see the mock and components in colored boxes.

thinking-in-react-components

I will not discuss this topic longer here. To learn more about how to think in React, click here.

Another point: Before, we code HTML and JavaScript separately on a web page. In React, we code HTML inside JavaScript. This is made possible through JSX. To learn more about JSX, click here.

React concepts can be hard to grasp at first, but you will get there. If you do actual coding with React, you will understand it better and faster. This is why our step-by-step React CRUD tutorial below will be very useful.

3.0 Technologies Used In This Tutorial

Here we will learn how to create, read update and delete database records – CRUD operations with PHP, MySQL, React, Babel, jQuery and Bootstrap.

Why do I use these technologies for this React CRUD tutorial? Here are my reasons:

  1. They work.
  2. Most audience of our blog are very familiar with these technologies.
  3. The goal of this tutorial is for you to learn how to use React.
  4. React is only the V in MVC.
  5. React don’t make assumptions about the rest of your technology stack.

Now, let’s take a look at the roles of each technology that we will use:

  • PHP – will handle server side script.
  • MySQL – will store our data.
  • React – will make our UI fast and interactive.
  • Babel – will compile our JavaScript so we don’t have to wait for browser support.
  • jQuery – will do AJAX requests. React official docs shows jQuery examples.
  • Bootstrap – will make our UI look better.

For those who ask, React can work with AngularJS. In short, it can work with the MEAN (mongoDB, Express, AngularJS and NodeJS) framework. We will have another tutorial for that soon! Please subscribe so I can notify you when it is done.

4.0 Set Up 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 in this page because we want you to focus on learning how to code with React, 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 React 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 JSON Data Using React?” 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 Basic Files & Folders

5.1 File Structure

Our LEVEL 1 source code will have the following files and folders.

├─app/
├───assets/
├──────css/
├─────────custom.css
├───product/
├──────create_product.component.js
├──────delete_product.component.js
├──────product_table_row.component.js
├──────product_table.component.js
├──────read_one_product.component.js
├──────read_products.component.js
├──────top_actions.component.js
├──────update_product.component.js
├───main.component.js
├─index.html

The functions of each files above were explained in different sections of this tutorial.

5.2 Create index.html file

The index.html is the first file that will run on our browser. It contains our:

  • Bootstrap CSS – to make our web app look better.
  • Custom CSS – Bootstrap CSS cannot do it all so we need this custom styles.
  • Container DIV tag – our React application will be injected in this DIV tag.
  • React libraries – JavaScript files needed to run a React web application.
  • React custom codes – main custom codes of our React web application
  • jQuery library – will be used for AJAX requests. It is required by Bootstrap JavaScript as well.
  • Bootstrap JavaScript – needed to make use of more Bootstrap features like drop-down menu, etc.

Create index.html and put the following code.

<!DOCTYPE html>
<html lang="en">
<head>

    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">

    <title>LEVEL 1 - React CRUD Tutorial - codeofaninja.com</title>

    <!-- Bootstrap CSS -->
	<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet" media="screen" />

    <!-- Custom CSS -->
	<link href="app/assets/css/custom.css" rel="stylesheet" media="screen" />

</head>
<body>

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

        <div class="page-header">
            <h1>Loading...</h1>
        </div>

        <!-- placeholder for rendering react components -->
        <div id='content'></div>

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

<!-- react js -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/babel-core/5.8.34/browser.min.js"></script>

<!-- react code -->
<script type="text/babel" src="app/product/update_product.component.js"></script>
<script type="text/babel" src="app/product/create_product.component.js"></script>
<script type="text/babel" src="app/product/read_one_product.component.js"></script>
<script type="text/babel" src="app/product/delete_product.component.js"></script>
<script type="text/babel" src="app/product/product_table_row.component.js"></script>
<script type="text/babel" src="app/product/product_table.component.js"></script>
<script type="text/babel" src="app/product/top_actions.component.js"></script>
<script type="text/babel" src="app/product/read_products.component.js"></script>
<script type="text/babel" src="app/main.component.js"></script>

<!-- jQuery library required by bootsrap js -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>

<!-- bootstrap JavaScript -->
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>

</body>
</html>

5.3 Create custom CSS file

As said earlier, Bootstrap CSS cannot do it all so we need this custom styles.

  • Create “app” folder.
  • Create “assets” folder inside “app” folder.
  • Create “css” folder inside “assets” folder.
  • Create “custom.css” file inside “css” folder.
  • Open “custom.css” file and put the following code.
.text-align-center{ text-align:center; }
.margin-zero{ margin:0; }
.overflow-hidden{ overflow:hidden; }
.margin-bottom-1em{ margin-bottom:1em; }
.m-r-1em{ margin-right:1em; }

5.4 Create main.component.js file

Our “main component” will hold all other components of our react application.

Open “app” folder. Create “main.component.js” file. Put the following code.

// component that decides which main component to load: read or create/update
var MainApp = React.createClass({

	// initial mode is 'read' mode
    getInitialState: function(){
        return {
            currentMode: 'read',
            productId: null
        };
    },

	// used when use clicks something that changes the current mode
    changeAppMode: function(newMode, productId){
        this.setState({currentMode: newMode});
            if(productId !== undefined){
            this.setState({productId: productId});
        }
    },

	// render the component based on current or selected mode
    render: function(){

        var modeComponent =
            <ReadProductsComponent
            changeAppMode={this.changeAppMode} />;

        switch(this.state.currentMode){
            case 'read':
                break;
            case 'readOne':
                modeComponent = <ReadOneProductComponent productId={this.state.productId} changeAppMode={this.changeAppMode}/>;
                break;
            case 'create':
                modeComponent = <CreateProductComponent changeAppMode={this.changeAppMode}/>;
                break;
            case 'update':
                modeComponent = <UpdateProductComponent productId={this.state.productId} changeAppMode={this.changeAppMode}/>;
                break;
            case 'delete':
                modeComponent = <DeleteProductComponent productId={this.state.productId} changeAppMode={this.changeAppMode}/>;
                break;
            default:
                break;
        }

        return modeComponent;
    }
});

// go and render the whole React component on to the div with id 'content'
ReactDOM.render(
    <MainApp />,
    document.getElementById('content')
);

5.5 Create “products” scripts

We need several JavaScript files that contains React code to make our application work.

Open “app” folder. Create “product” folder inside “app” folder.

Create the following JavaScript files.

  • update_product.component.js
  • create_product.component.js
  • read_one_product.component.js
  • delete_product.component.js
  • product_table_row.component.js
  • product_table.component.js
  • top_actions.component.js
  • read_products.component.js

Currently, those JavaScript files are empty. Where are the codes?

We will see the codes on the next several sections of this tutorial.

5.6 Output

Since our JavaScript files are empty, the output of all we did above is a blank page.

See it for yourself by running http://localhost/react-crud-level-1/index.html on your browser.

6.0 How To Read JSON Data Using React?

6.1 Create “Read Products” Component

This component will hold the product records using an HTML table. It will hold the “create product” button as well. The button or “top actions” are located on the upper right corner of this component.

Open “app” folder.
Open “products” folder inside “app” folder.
Open “read_products.component.js” file.
Put the following code in it and save it.

// component that contains all the logic and other smaller components
// that form the Read Products view
window.ReadProductsComponent = React.createClass({
    getInitialState: function() {
        return {
            products: []
        };
    },

    // on mount, fetch all products and stored them as this component's state
    componentDidMount: function() {

        this.serverRequest = $.get("http://localhost/api/product/read.php", function (products) {
            this.setState({
                products: products.records
            });
        }.bind(this));
    },

    // on unmount, kill product fetching in case the request is still pending
    componentWillUnmount: function() {
        this.serverRequest.abort();
    },

    // render component on the page
    render: function() {
        // list of products
        var filteredProducts = this.state.products;
        $('.page-header h1').text('Read Products');

        return (
            <div className='overflow-hidden'>
                <TopActionsComponent changeAppMode={this.props.changeAppMode} />

                <ProductsTable
                    products={filteredProducts}
                    changeAppMode={this.props.changeAppMode} />
            </div>
        );
    }
});

6.2 Create “Top Actions” Component

The previous section makes use of “TopActionsComponent”. This component holds our “create product” button. You can add more buttons in this component. For now, we have only one.

Still in the “product” folder. Open “top_actions.component.js” file.
Put the following code in it and save it.

// component that contains the functionalities that appear on top of
// the products table: create product
window.TopActionsComponent = React.createClass({
    render: function(){
        return (
            <div>
                <a href='#'
                    onClick={() => this.props.changeAppMode('create')}
                    className='btn btn-primary margin-bottom-1em'> Create product
                </a>
            </div>
        );
    }
});

6.3 Create “ProductsTable” Component

We previously made use of “ProductsTable” component as well. This will hold the table header and table rows with products data.

Still in the “product” folder. Open “product_table.component.js” file.
Put the following code in it and save it.

// component for the whole products table
window.ProductsTable = React.createClass({
    render: function() {

    var rows = this.props.products
        .map(function(product, i) {
            return (
                <ProductRow
                    key={i}
                    product={product}
                    changeAppMode={this.props.changeAppMode} />
            );
        }.bind(this));

        return(
            !rows.length
                ? <div className='alert alert-danger'>No products found.</div>
                :
                <table className='table table-bordered table-hover'>
                    <thead>
                        <tr>
                            <th>Name</th>
                            <th>Description</th>
                            <th>Price</th>
                            <th>Category</th>
                            <th>Action</th>
                        </tr>
                    </thead>
                    <tbody>
                        {rows}
                    </tbody>
                </table>
        );
    }
});

6.4 Create “ProductRow” Component

On the previous section, we used the “ProductRow” component. This component will hold a table row with product data. It will hold three buttons as well. The “Read One”, “Edit” and “Delete” product button.

Still in the “product” folder. Open “product_table_row.component.js” file.
Put the following code in it and save it.

// component that renders a single product
window.ProductRow = React.createClass({
    render: function() {
    return (
        <tr>
            <td>{this.props.product.name}</td>
            <td>{this.props.product.description}</td>
            <td>${parseFloat(this.props.product.price).toFixed(2)}</td>
            <td>{this.props.product.category_name}</td>
            <td>
                <a href='#'
                    onClick={() => this.props.changeAppMode('readOne', this.props.product.id)}
                    className='btn btn-info m-r-1em'> Read One
                </a>
                <a href='#'
                    onClick={() => this.props.changeAppMode('update', this.props.product.id)}
                    className='btn btn-primary m-r-1em'> Edit
                </a>
                <a
                    onClick={() => this.props.changeAppMode('delete', this.props.product.id)}
                    className='btn btn-danger'> Delete
                </a>
            </td>
        </tr>
        );
    }
});

6.5 Output

If we completed the steps above, the output should be an HTML table with product data on each table row. The “Read One”, “Edit” and “Delete” buttons should be seen on each table row as well.

7.0 How To Create or Insert Data Using React?

7.1 Create “CreateProductComponent” Class

The “CreateProductComponent” class will contain the logic and HTML of our app’s “Create Product” feature.

window.CreateProductComponent = React.createClass({
	// initial component states will be here
});

7.2 Initialize component state

We need to initialize states for this component. Usually, initial states are empty as seen in the getInitialState method.

When component was mounted, we will get the list of categories from the API. The returned categories will be used in the form’s “categories” dropdown field.

When component was unmounted, we need to stop the server request, just in case the request is still pending.

Replace “// initial component states will be here” of the previous section with the following code.

// initialize values
getInitialState: function() {
	return {
		categories: [],
		selectedCategoryId: -1,
		name: '',
		description: '',
		price: '',
		successCreation: null
	};
},

// on mount, get all categories and store them in this component's state
componentDidMount: function() {
	this.serverRequest = $.get("http://localhost/api/category/read.php", function (categories) {
		this.setState({
			categories: categories.records
		});
	}.bind(this));

	$('.page-header h1').text('Create product');
},

// on unmount, stop getting categories in case the request is still loading
componentWillUnmount: function() {
	this.serverRequest.abort();
},

// handle form field changes here

7.3 Handle form field changes

We need methods to keep track of change on our form fields. As user types or changes a field’s value, it is saved to the component’s state.

Replace “// handle form field changes here” of the previous section with the following code.

// handle category change
onCategoryChange: function(e) {
	this.setState({selectedCategoryId: e.target.value});
},

// handle name change
onNameChange: function(e) {
	this.setState({name: e.target.value});
},

// handle description change
onDescriptionChange: function(e) {
	this.setState({description: e.target.value});
},

// handle price change
onPriceChange: function(e) {
	this.setState({price: e.target.value});
},

// handle save button here

7.4 Handle “Save” button

When user clicks the “save” button, form data must be sent to the API. This way, data will be saved on the database.

We need the “onSave” method to handle this event.

Replace “// handle save button here” of the previous section with the following code.

// handle save button clicked
onSave: function(e){

	// data in the form
	var form_data={
		name: this.state.name,
		description: this.state.description,
		price: this.state.price,
		category_id: this.state.selectedCategoryId
	};

	// submit form data to api
	$.ajax({
		url: "http://localhost/api/product/create.php",
		type : "POST",
		contentType : 'application/json',
		data : JSON.stringify(form_data),
		success : function(response) {

			// api message
			this.setState({successCreation: response['message']});

			// empty form
			this.setState({name: ""});
			this.setState({description: ""});
			this.setState({price: ""});
			this.setState({selectedCategoryId: -1});

		}.bind(this),
		error: function(xhr, resp, text){
			// show error to console
			console.log(xhr, resp, text);
		}
	});

	e.preventDefault();
},

// render component here

7.5 Render “Create Product” HTML Form

Now you’re asking: Where’s the HTML form?

Our HTML form is in the “render” method.

Replace “// render component here” of the previous section with the following code.

render: function() {

    // make categories as option for the select tag.
    var categoriesOptions = this.state.categories.map(function(category){
        return (
            <option key={category.id} value={category.id}>{category.name}</option>
        );
    });

    /*
    - tell the user if a product was created
    - tell the user if unable to create product
    - button to go back to products list
    - form to create a product
    */
    return (
    <div>
        {

            this.state.successCreation == "Product was created." ?
                <div className='alert alert-success'>
                    Product was saved.
                </div>
            : null
        }

        {

            this.state.successCreation == "Unable to create product." ?
                <div className='alert alert-danger'>
                    Unable to save product. Please try again.
                </div>
            : null
        }

        <a href='#'
            onClick={() => this.props.changeAppMode('read')}
            className='btn btn-primary margin-bottom-1em'> Read Products
        </a>


        <form onSubmit={this.onSave}>
            <table className='table table-bordered table-hover'>
            <tbody>
                <tr>
                    <td>Name</td>
                    <td>
                        <input
                        type='text'
                        className='form-control'
                        value={this.state.name}
                        required
                        onChange={this.onNameChange} />
                    </td>
                </tr>

                <tr>
                    <td>Description</td>
                    <td>
                        <textarea
                        type='text'
                        className='form-control'
                        required
                        value={this.state.description}
                        onChange={this.onDescriptionChange}>
                        </textarea>
                    </td>
                </tr>

                <tr>
                    <td>Price ($)</td>
                    <td>
                        <input
                        type='number'
                        step="0.01"
                        className='form-control'
                        value={this.state.price}
                        required
                        onChange={this.onPriceChange}/>
                    </td>
                </tr>

                <tr>
                    <td>Category</td>
                    <td>
                        <select
                        onChange={this.onCategoryChange}
                        className='form-control'
                        value={this.state.selectedCategoryId}>
                        <option value="-1">Select category...</option>
                        {categoriesOptions}
                        </select>
                    </td>
                </tr>

                <tr>
                    <td></td>
                    <td>
                        <button
                        className='btn btn-primary'
                        onClick={this.onSave}>Save</button>
                    </td>
                </tr>
                </tbody>
            </table>
        </form>
    </div>
    );
}

7.6 Output

When you click the “Create Product” button, output that you should see is an HTML form with fields: Name, description, price and category drop-down list. A “Save” button should be seen as well.

Try to fill-out the form and click the “Save” button. Click the “Read Products” button and see if your record is in the list. If it’s there, it means our React app is working.

8.0 How To Read One Data Using React?

8.1 Create “ReadOneProductComponent” Class

The “ReadOneProductComponent” class will contain the logic and HTML of our app’s “Read One Product” feature.

// component that contains the logic to read one product
window.ReadOneProductComponent = React.createClass({
	// initial component state will be here
});

8.2 Initialize component state

Initial states are empty as seen in the getInitialState method.

When component was mounted, we will get the product data from the API. The returned data will be set to component state. The state’s value will be used in HTML table.

When component was unmounted, we need to stop the server request, just in case the request is still pending.

Replace “// initial component state will be here” of the previous section with the following code.

getInitialState: function() {
    // Get this product fields from the data attributes we set on the
    // #content div, using jQuery
    return {
        id: 0,
        name: '',
        description: '',
        price: 0,
        category_name: ''
    };
},

// on mount, read product data and them as this component's state
componentDidMount: function(){

    var productId = this.props.productId;

    this.serverRequestProd = $.get("http://localhost/api/product/read_one.php?id=" + productId,
        function (product) {
            this.setState({category_name: product.category_name});
            this.setState({id: product.id});
            this.setState({name: product.name});
            this.setState({description: product.description});
            this.setState({price: product.price});
        }.bind(this));

    $('.page-header h1').text('Read Product');
},

// on unmount, kill categories fetching in case the request is still pending
componentWillUnmount: function() {
    this.serverRequestProd.abort();
},

// render component html will be here

8.3 Render Component HTML

We will use the “render” method again to render this “ReadOneProductComponent” HTML on the web page.

Replace “// render component html will be here” of the previous section with the following code.

render: function() {

    return (
        <div>
            <a href='#'
                onClick={() => this.props.changeAppMode('read')}
                className='btn btn-primary margin-bottom-1em'>
                Read Products
            </a>

            <form onSubmit={this.onSave}>
                <table className='table table-bordered table-hover'>
                    <tbody>
                    <tr>
                        <td>Name</td>
                        <td>{this.state.name}</td>
                    </tr>

                    <tr>
                        <td>Description</td>
                        <td>{this.state.description}</td>
                    </tr>

                    <tr>
                        <td>Price ($)</td>
                        <td>${parseFloat(this.state.price).toFixed(2)}</td>
                    </tr>

                    <tr>
                        <td>Category</td>
                        <td>{this.state.category_name}</td>
                    </tr>

                    </tbody>
                </table>
            </form>
        </div>
    );
}

8.4 Output

When you click the “Read One” button, you should see an HTML table with a product’s data. The “Read Products” button should be seen as well.

9.0 How To Update Data Using React?

9.1 Create “UpdateProductComponent” Class

The “UpdateProductComponent” class will contain the logic and HTML of our app’s “Update Product” feature.

// component that contains the logic to update a product
window.UpdateProductComponent = React.createClass({
	// initial component states will be here
});

9.2 Initialize component state

Initial component states are empty as seen in the getInitialState method.

When component was mounted, we will get the list of categories from the API. The returned categories will be used in the form’s “categories” dropdown field. We get a product data based on given product ID as well. This will fill out the “update product” form.

When component was unmounted, we need to stop both server requests, just in case any of the request is still pending.

Replace “// initial component states will be here” of the previous section with the following code.

getInitialState: function() {
    // Get this product fields from the data attributes we set on the
    // #content div, using jQuery
    return {
        categories: [],
        selectedCategoryId: 0,
        id: 0,
        name: '',
        description: '',
        price: 0,
        successUpdate: null
    };
},

// on mount, fetch all categories and one product data to stored them as this component's state
componentDidMount: function(){

	// read categories
    this.serverRequestCat = $.get("http://localhost/api/category/read.php",
        function (categories) {
            this.setState({
                categories: categories.records
            });
        }.bind(this));

	// read one product data
    var productId = this.props.productId;
    this.serverRequestProd = $.get("http://localhost/api/product/read_one.php?id=" + productId,
        function (product) {
            this.setState({selectedCategoryId: product.category_id});
            this.setState({id: product.id});
            this.setState({name: product.name});
            this.setState({description: product.description});
            this.setState({price: product.price});
        }.bind(this));

    $('.page-header h1').text('Update product');
},

// on unmount, kill categories fetching in case the request is still pending
componentWillUnmount: function() {
    this.serverRequestCat.abort();
    this.serverRequestProd.abort();
},

// handle form field changes here

9.3 Handle form field changes

We need methods to keep track of any input changes on our form fields. As user types or changes a field’s value, it is saved to the component’s state.

Replace “// handle form field changes here” of the previous section with the following code.

// handle category change
onCategoryChange: function(e){
    this.setState({selectedCategoryId: e.target.value});
},

// handle name change
onNameChange: function(e){
    this.setState({name: e.target.value});
},

// handle description change
onDescriptionChange: function(e){
    this.setState({description: e.target.value});
},

// handle price change
onPriceChange: function(e){
    this.setState({price: e.target.value});
},

// handle save changes button here

9.4 Handle “Save Changes” button

When user clicks the “Save Changes” button, form data must be sent to the API. The updated data will be saved on the database.

We will create the “onSave” method to handle this event.

Replace “// handle save changes button here” of the previous section with the following code.

// handle save changes button clicked
onSave: function(e){

    // data in the form
    var form_data={
        id: this.state.id,
        name: this.state.name,
        description: this.state.description,
        price: this.state.price,
        category_id: this.state.selectedCategoryId
    };

    // submit form data to api
    $.ajax({
        url: "http://localhost/api/product/update.php",
        type : "POST",
        contentType : 'application/json',
        data : JSON.stringify(form_data),
        success : function(response) {
            this.setState({successUpdate: response['message']});
        }.bind(this),
        error: function(xhr, resp, text){
            // show error to console
            console.log(xhr, resp, text);
        }
    });

    e.preventDefault();
},

// render component here

9.5 Render “Update Product” HTML Form

Now you’re asking: Where’s the HTML form filled-out with product data?

Our HTML form is in the “render” method below.

Replace “// render component here” of the previous section with the following code.

render: function() {
    var categoriesOptions = this.state.categories.map(function(category){
        return (
            <option key={category.id} value={category.id}>{category.name}</option>
        );
    });

    return (
        <div>
            {
                this.state.successUpdate == "Product was updated." ?
                    <div className='alert alert-success'>
                        Product was updated.
                    </div>
                : null
            }

            {
                this.state.successUpdate == "Unable to update product." ?
                    <div className='alert alert-danger'>
                        Unable to update product. Please try again.
                    </div>
                : null
            }

            <a href='#'
                onClick={() => this.props.changeAppMode('read')}
                className='btn btn-primary margin-bottom-1em'>
                Read Products
            </a>

            <form onSubmit={this.onSave}>
                <table className='table table-bordered table-hover'>
                    <tbody>
                    <tr>
                        <td>Name</td>
                        <td>
                            <input
                                type='text'
                                className='form-control'
                                value={this.state.name}
                                required
                                onChange={this.onNameChange} />
                        </td>
                    </tr>

                    <tr>
                        <td>Description</td>
                        <td>
                            <textarea
                                type='text'
                                className='form-control'
                                required
                                value={this.state.description}
                                onChange={this.onDescriptionChange}></textarea>
                        </td>
                    </tr>

                    <tr>
                        <td>Price ($)</td>
                        <td>
                            <input
                                type='number'
                                step="0.01"
                                className='form-control'
                                value={this.state.price}
                                required
                                onChange={this.onPriceChange}/>
                        </td>
                    </tr>

                    <tr>
                        <td>Category</td>
                        <td>
                            <select
                                onChange={this.onCategoryChange}
                                className='form-control'
                                value={this.state.selectedCategoryId}>
                                <option value="-1">Select category...</option>
                                {categoriesOptions}
                                </select>
                        </td>
                    </tr>

                    <tr>
                        <td></td>
                        <td>
                            <button
                                className='btn btn-primary'
                                onClick={this.onSave}>Save Changes</button>
                        </td>
                    </tr>

                    </tbody>
                </table>
            </form>
        </div>
    );
}

9.6 Output

When you click the “Edit” button, output that you should see is an HTML form with fields: Name, description, price and category drop-down list. These field must be filled out with product data to be edited.

A “Save” button should be seen as well.

Try to edit the form and click the “Save Changes” button. Click the “Read Products” button and see if your record was updated in the list. If it’s there, it means our React app is working.

10.0 How To Delete Data Using React?

10.1 Create “DeleteProductComponent” Class

The “DeleteProductComponent” class will contain the logic and HTML of our app’s “Delete Product” feature.

// component that contains the logic to delete a product
window.DeleteProductComponent = React.createClass({
	// componentDidMount will be here
});

10.2 Change Page Title

When this component was mounted, we’ll just have to change the page title.

Replace “// componentDidMount will be here” of the previous section with the following code.

// on mount, change header text
componentDidMount: function(){
	$('.page-header h1').text('Delete Product');
},

// onDelete will be here

10.3 Handle “Yes” Button

If user clicked the “Yes” button, record will be deleted. It triggers our “onDelete” method below.

Replace “// onDelete will be here” of the previous section with the following code.

// handle single row deletion
onDelete: function(e){

    // product to delete
    var productId = this.props.productId;

    // submit form data to api
    $.ajax({
        url: "http://localhost/api/product/delete.php",
        type : "POST",
        contentType : 'application/json',
        data : JSON.stringify({'id' : productId}),
        success : function(response) {
            this.props.changeAppMode('read');
        }.bind(this),
        error: function(xhr, resp, text){
            // show error in console
            console.log(xhr, resp, text);
        }
    });
},

// render will be here

10.4 Render “Delete Confirmation” Box

Our “render” method contains the message prompt HTML. It asks the user if he’s sure to delete a record.

Replace “// render will be here” of the previous section with the following code.

render: function(){

    return (
        <div className='row'>
            <div className='col-md-3'></div>
            <div className='col-md-6'>
                <div className='panel panel-default'>
                	<div className='panel-body text-align-center'>Are you sure?</div>
                	<div className='panel-footer clearfix'>
                		<div className='text-align-center'>
                            <button onClick={this.onDelete}
                                className='btn btn-danger m-r-1em'>Yes</button>
                            <button onClick={() => this.props.changeAppMode('read')}
                                className='btn btn-primary'>No</button>
                		</div>
                	</div>
                </div>
            </div>
            <div className='col-md-3'></div>
        </div>
    );
}

10.5 Output

When user click the “Delete” button, a message prompt will be shown. It asks the user to confirm the deletion of a record. Specifically, message will say “Are you sure?”.

If user clicked “Yes”, record will be deleted from the database. User will be redirected to the product list. If user clicked “No”, user will be redirected to the product list.

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 files to your server directory.
  2. Set up the “api” by following the README.txt inside the “api” folder.
  3. Open your browser and run index.html
  4. If you can see the list of “product” records, it means your set up is correct.

12.0 Download LEVEL 1 Source Code

FEATURES LEVEL 1
PDO extension used YES
Bootstrap UI enabled YES
Facebook React YES
Create product YES
Read product YES
Update product YES
Delete product YES
Category selection for create and update product. YES
Price display with dollar sign YES
SQL file in “dev” folder YES
Download Now

13.0 Download LEVEL 2 Source Code

FEATURES LEVEL 2
All features of LEVEL 1 above YES
Search records YES
Show records when search box is empty YES
Routing works for search, page, create, edit and delete pages YES
Export CSV YES
Multiple delete YES
Pagination YES
Pagination in search YES
Go to page number YES
Limit go to page number based on number of pages YES
Buttons with glyphicons YES
Download Now

14.0 Download ALL LEVELS

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

Download Now

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 React & PHP Rest API 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?

Next, we will learn how to create, read, update and delete records with AngularJS, also known as Angular 1.x. Click the following link: AngularJS CRUD Tutorial

16.0 Related Tutorials

17.0 Online Resources

Here are useful resources related to React.

18.0 Some 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!

Thanks for reading our step by step tutorial about React CRUD Tutorial!

Home JavaScript

AngularJS CRUD Example with Material Design – Step by Step Guide!


Previously, we learned how to create, read, update and delete database records with our React CRUD Tutorial. Today, we will learn how to do the same CRUD operations with AngularJS, Angular Material and REST API.

Contents of this tutorial include:

1.0 Tutorial Overview
2.0 Program Output – AngularJS CRUD Example
3.0 Set Up The REST API

4.0 Basic Files & Folders
4.1 File Structure
4.2 Create index.html file
4.3 Include Angular Material, Roboto Font and Custom CSS
4.4 AngularJS and Angular Material JavaScript
4.6 Custom JavaScript
4.7 Place AngularJS app container
4.8 Output

5.0 How To Read JSON Data Using AngularJS?
5.1 Create Template for products list
5.2 Create “products” controller
5.3 Create “products” factory
5.4 Output

6.0 How To Create or 6Insert Data Using AngularJS?
6.1 Add “create” product button
6.2 Show “create product” form in dialog box
6.3 Create dialog controller
6.4 Create “create_product” HTML form template
6.5 Add “createProduct” method in controller
6.6 Clear form contents
6.7 Show messages to user
6.8 Add “createProduct” method in factory
6.9 Output

7.0 How To Read One Data Using AngularJS?
7.1 Add “Read One” button in products list
7.2 Show product information in dialog box
7.3 Create “read_one_product.template.html” file
7.4 Add “readOneProduct” method in factory
7.5 Output

8.0 How To Update Data Using AngularJS?
8.1 Add “Edit” button in products list
8.2 Show editable product information in dialog box
8.3 Create “update_product.template.html” file
8.4 Add “updateProduct” method in controller
8.5 Add “updateProduct” method in factory
8.6 Output

9.0 How To Delete Data Using AngularJS?
9.1 Add “delete” button in products list
9.2 Ask user to confirm product deletion
9.3 Add “deleteProduct” function in controller
9.4 Add “deleteProduct” function in factory
9.5 Output

10.0 How To Search Data Using AngularJS?
10.1 Allow users to type search keywords
10.2 Add “searchProducts” function in controller
10.3 Add “searchProducts” function in factory
10.4 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

1.0 Tutorial Overview

What is AngularJS? It is one of the leading framework for building large JavaScript applications that are easy to maintain.

It makes the development faster because we can implement useful concepts like dependency injection, two-way data binding, reusable code and unit testing.

This tutorial will focus on creating, reading, updating, deleting and searching database records. We will do it using AngularJS and Angular Material as it’s user interface component.

JSON data will be handled by the REST API built using PHP.

2.0 Program Output – AngularJS CRUD Example

2.1 LEVEL 1 Source Code Output


2.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!

3.0 Set Up 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 AngularJS, 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 AngularJS app. The list of products will be displayed in the page with buttons like “Read One”, “Update” and “Delete”. You will see it in the “How To Read JSON Data Using AngularJS?” section of this tutorial.

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

4.0 Basic Files & Folders

4.1 File Structure

At the end of this tutorial, we will have the following file structure.
├─ app/
├─── assets/
├────── css/
├───────── custom.css
├─── products/
├────── create_product.template.html
├────── products.controller.js
├────── products.factory.js
├────── read_one_product.template.html
├────── read_products.template.html
├────── update_product.template.html
├─── app.js
├─ index.html

4.2 Create index.html file

Create index.html file. Open that file and put the following basic HTML code.

<!DOCTYPE html>
<html>
<head>

    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">

    <title>Read Products</title>

</head>
<body>

<!-- app container will be here -->

</body>
</html>

4.3 Include Angular Material, Roboto Font and Custom CSS

We are going to use CSS files from Google CDN. Place the following code inside “head” tag, under “title” tag of the previous section.

<!-- angular material style sheet -->
<link rel="stylesheet" href="http://ajax.googleapis.com/ajax/libs/angular_material/1.1.0/angular-material.min.css">

<!-- roboto font -->
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700,400italic">

<!-- include custom CSS -->
<link rel="stylesheet" href="app/assets/css/custom.css" />

Our “custom.css” file does not exist yet so we have to create it. We will put some CSS as well to style some parts of our application.

  1. Create “app” folder.
  2. Inside “app” folder, create “assets” folder.
  3. Inside “assets” folder, create “css” folder.
  4. Inside “css” folder, create “custom.css” file.
  5. Open “custom.css” file and place the following code.
md-dialog{ width:50%; }
.m-20px-0{ margin:20px 0; }
.m-b-20px{ margin-bottom:20px; }
.m-b-0px{ margin-bottom:0px; }
.md-info{ background-color:#2196F3 !important; color:#ffffff !important; }
.md-danger{ background-color:#D32F2F !important; color:#ffffff !important; }
.w-5-pct{ width:5%; }
.w-10-pct{ width:10%; }
.w-20-pct{ width:20%; }
.w-30-pct{ width:30%; }
.w-35-pct{ width:35%; }
.w-40-pct{ width:40%; }
.w-50-pct{ width:50%; }
.w-60-pct{ width:60%; }
.w-70-pct{ width:70%; }
.w-80-pct{ width:80%; }
.w-90-pct{ width:90%; }
.w-100-pct{ width:100%; }
.t-a-c{ text-align:center; }
.t-a-l{ text-align:left; }
.margin-bottom-1em{ margin-bottom:1em; }

4.4 AngularJS and Angular Material JavaScript

We are going to use AngularJS JavaScript files from Google CDN. Place the following code before the closing “body” tag.

<!-- include angular js -->
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.1/angular.min.js"></script>

<!-- needed for angular material -->
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.5.5/angular-animate.min.js"></script>
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.5.5/angular-aria.min.js"></script>
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.5.5/angular-messages.min.js"></script>

<!-- angular material Library -->
<script src="http://ajax.googleapis.com/ajax/libs/angular_material/1.1.0/angular-material.min.js"></script>

4.6 Custom JavaScript

Place the following code after the previous section’s code.

<!-- app -->
<script type="text/javascript" src="app/app.js"></script>

<!-- products controller -->
<script type="text/javascript" src="app/products/products.controller.js"></script>

<!-- products factory -->
<script type="text/javascript" src="app/products/products.factory.js"></script>

The JavaScript files above does not exist yet so we will create it.

  1. Open “app” folder.
  2. Inside “app” folder, create “app.js” file.
  3. Inside “app” folder again, create “products” folder.
  4. Inside “products” folder, create “products.controller.js” and “products.factory.js” files.

Open “app.js” file and place the following code.

var app = angular.module('myApp', ['ngMaterial']);

We added ‘ngMaterial’ parameter to enable our Angular Material user interface. We will explain and place AngularJS codes inside “products.controller.js” and “products.factor.js” files as we progress in this tutorial.

4.7 Place AngularJS app container

The “read_products.template.html” will hold the template for displaying list of products.

Find

<!-- app container will be here -->

in index.html and replace it with the following code.

<!-- container of our app -->
<div class="container" ng-app="myApp">

    <!-- read products template -->
    <ng-include src="'./app/products/read_products.template.html'"></ng-include>

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

The “read_products.template.html” file does not exist yet so we will create it.

  1. Open “app” folder.
  2. Inside “app” folder, open “products” folder.
  3. Inside “products” folder, create “read_products.template.html” file.

4.8 Output

After doing all the steps above. The output is a blank page. Yes, a blank page for now. But for sure, we will see something here after you complete the next section.

5.0 How To Read JSON Data Using AngularJS?

5.1 Template for products list

Open “read_products.template.html” file and place the following code.

<div layout="row" ng-controller="productsController" ng-cloak>
    <div flex="10"></div>

    <div flex="80" class='m-20px-0'>

        <!-- page title & 'create product' button -->
        <md-toolbar class="md-hue-2">
            <div class="md-toolbar-tools">
                <!-- page title -->
                <div flex md-truncate>
                    <h3 class="md-headline">Products</h3>
                </div>

                <!-- 'create' product button will be here -->
            </div>
        </md-toolbar>

        <!-- 'search' bar will be here -->

        <md-content flex>
            <!-- show product record list -->
            <md-list ng-init="readProducts()">
                <md-list-item class="md-3-line" ng-repeat="product in products">

                    <!-- product information -->
                    <div class="md-list-item-text">
                        <h3>{{product.name}}</h3>
                        <h4>{{product.description}}</h4>
                        <p>${{product.price}}</p>
                    </div>

                    <!-- 'read one', 'edit' and 'delete' buttons -->
                    <div class="md-secondary-container">
						<!-- 'read one' button will be here -->
						<!-- 'edit' button will be here -->
						<!-- 'delete' button will be here -->
                    </div>
                    <md-divider ng-if="!$last"></md-divider>
                </md-list-item>
            </md-list>
        </md-content>
    </div>

    <div flex="10"></div>
</div> <!-- end row -->

5.2 Create “products” controller

  1. Open “app” folder.
  2. Inside “app” folder, open “products” folder.
  3. Inside “products” folder, create “products.controller.js” file.
  4. Open “products.controller.js” file and place the following code.
app.controller('productsController', function($scope, $mdDialog, $mdToast, productsFactory){

	// read products
	$scope.readProducts = function(){

		// use products factory
		productsFactory.readProducts().then(function successCallback(response){
			$scope.products = response.data.records;
		}, function errorCallback(response){
			$scope.showToast("Unable to read record.");
		});

	}
	
	// showCreateProductForm will be here
	
	// DialogController will be here
});

5.3 Create “products” factory

Why do we use “factory” in AngularJS? We use it to make the code reusable.

Methods in factories can be used in different controllers or parts of your application. If there will be a need for change, you don’t have to go and change several parts of the application that uses the same code.

  1. Open “products.factory.js” file.
  2. Create “products.factory.js” file and place the following code.
app.factory("productsFactory", function($http){

    var factory = {};

    // read all products
    factory.readProducts = function(){
        return $http({
            method: 'GET',
            url: 'http://localhost/api/product/read.php'
        });
    };
	
	// createProduct will be here
	
	return factory;
});

5.4 Output

You should see the list of products. Each row should have product name, description and price.

6.0 How To Create or Insert Data Using AngularJS?

6.1 Add “create” product button

We need this button to show a form where user can enter new product information.

  1. Open “read_products.template.html”.
  2. Find
    <!-- 'create' product button will be here -->
  3. Replace it with the following code.
<!-- button for creating product -->
<md-button class="md-raised" ng-click="showCreateProductForm()">Create</md-button>

6.2 Show “create product” form in dialog box

  1. Open “products.controller.js” file.
  2. Find “// showCreateProductForm will be here” and replace it with the following code.
// show 'create product form' in dialog box
$scope.showCreateProductForm = function(event){

	$mdDialog.show({
		controller: DialogController,
		templateUrl: './app/products/create_product.template.html',
		parent: angular.element(document.body),
		clickOutsideToClose: true,
		scope: $scope,
		preserveScope: true,
		fullscreen: true // Only for -xs, -sm breakpoints.
	});
}

// createProduct will be here

6.3 Create dialog controller

We are using Angular Material’s dialog box above. Users may click the ‘Cancel’ button. We need a method for that.

  1. Open “products.controller.js”.
  2. Find “// DialogController will be here” and replace it with the following code.
// methods for dialog box
function DialogController($scope, $mdDialog) {
	$scope.cancel = function() {
		$mdDialog.cancel();
	};
}

6.4 Create “create_product” HTML form template

Our dialog box loads an HTML temlate via “templateUrl” property.

  1. Open “app” folder.
  2. Inside “app” folder, open “products” folder.
  3. Inside “products” folder, create “create_product.template.html” file.
  4. Open “create_product.template.html” file and place the following code.
<md-dialog>
    <form ng-cloak>
        
        <md-toolbar>
            <div class="md-toolbar-tools">
                <h2>Create Product</h2>
            </div>
        </md-toolbar>

        <md-dialog-content>
            <div class="md-dialog-content">

				<!-- we are using ng-model to bind this view and the 'product model -->
                <md-input-container class="md-block">
                    <label>Name</label>
                    <input ng-model="name">
                </md-input-container>

                <md-input-container class="md-block">
                    <label>Description</label>
                    <input ng-model="description">
                </md-input-container>

                <md-input-container class="md-block">
                    <label>Price</label>
                    <input ng-model="price">
                </md-input-container>

            </div>
        </md-dialog-content>

        <md-dialog-actions layout="row">
            <md-button ng-click="cancel()">Cancel</md-button>
            <md-button ng-click="createProduct()" class="md-primary">Create</md-button>
        </md-dialog-actions>
    </form>
</md-dialog>

6.5 Add “createProduct” method in controller

  1. Open “products.controller.js”.
  2. Find “// createProduct will be here” and replace it with the following code.
// create new product
$scope.createProduct = function(){

	productsFactory.createProduct($scope).then(function successCallback(response){

		// tell the user new product was created
		$scope.showToast(response.data.message);

		// refresh the list
		$scope.readProducts();

		// close dialog
		$scope.cancel();

		// remove form values
		$scope.clearProductForm();

	}, function errorCallback(response){
		$scope.showToast("Unable to create record.");
	});
}

// readOneProduct will be here

6.6 Clear form contents

We need clearProductForm to clear form values.

Place the following code after the previous section’s code.

// clear variable / form values
$scope.clearProductForm = function(){
	$scope.id = "";
	$scope.name = "";
	$scope.description = "";
	$scope.price = "";
}

6.7 Show messages to user

We are using “toasts” to show messages to users.

Place the following code after the previous section’s code.

// show toast message
$scope.showToast = function(message){
	$mdToast.show(
		$mdToast.simple()
			.textContent(message)
			.hideDelay(3000)
			.position("top right")
	);
}

6.8 Add “createProduct” method in factory

  1. Open “products.factory.js” file.
  2. Find “// createProduct will be here” and replace it with the following code.
// create product
factory.createProduct = function($scope){
	return $http({
		method: 'POST',
		data: {
			'name' : $scope.name,
			'description' : $scope.description,
			'price' : $scope.price,
			'category_id' : 1
		},
		url: 'http://localhost/api/product/create.php'
	});
};

// readOneProduct will be here

6.9 Output

You should see a “create” button on the upper right corner of the page. Once this button is clicked, a dialog box with a “create product” form should appear.

7.0 How To Read One Data Using AngularJS?

7.1 Put “Read One” button in products list

  1. Open “read_products.template.html” file.
  2. Find
    <!-- 'read one' button will be here -->

    and replace it with the following code.

<md-button class="md-raised md-info" ng-click="readOne(product.id)">Read One</md-button>

7.2 Show product information in dialog box

If the user click “read one” button, a dialog box will appear with the product information.

  1. Open “products.controller.js” file.
  2. Find “// readOneProduct will be here” and replace it with the following code.
// retrieve record to fill out the form
$scope.readOneProduct = function(id){

	// get product to be edited
	productsFactory.readOneProduct(id).then(function successCallback(response){

		// put the values in form
		$scope.id = response.data.id;
		$scope.name = response.data.name;
		$scope.description = response.data.description;
		$scope.price = response.data.price;

		$mdDialog.show({
			controller: DialogController,
			templateUrl: './app/products/read_one_product.template.html',
			parent: angular.element(document.body),
			clickOutsideToClose: true,
			scope: $scope,
			preserveScope: true,
			fullscreen: true
		}).then(
			function(){},

			// user clicked 'Cancel'
			function() {
				// clear modal content
				$scope.clearProductForm();
			}
		);

	}, function errorCallback(response){
		$scope.showToast("Unable to retrieve record.");
	});

}

// showUpdateProductForm will be here

7.3 Create “read_one_product.template.html” file

The dialog box need an HTML template with product information.

  1. Open “products” folder.
  2. Inside “products” folder, create “read_one_product.template.html” file and place the following code.
<md-dialog>
    <form ng-cloak>

        <!-- dialog box title -->
        <md-toolbar>
            <div class="md-toolbar-tools">
                <h2>Read One Product</h2>
            </div>
        </md-toolbar>

        <md-dialog-content>
            <div class="md-dialog-content">

                <!-- display product information -->
                <md-input-container class="md-block">
                    <label>Name</label>
                    <input ng-model="name" disabled>
                </md-input-container>

                <md-input-container class="md-block">
                    <label>Description</label>
                    <input ng-model="description" disabled>
                </md-input-container>

                <md-input-container class="md-block">
                    <label>Price</label>
                    <input ng-model="price" disabled>
                </md-input-container>

            </div>
        </md-dialog-content>

        <!-- button to close the dialog box -->
        <md-dialog-actions layout="row">
            <md-button ng-click="cancel()">Cancel</md-button>
        </md-dialog-actions>
    </form>
</md-dialog>

7.4 Add “readOneProduct” method in factory

We will get the product information from the API.

  1. Open “products.factory.js” file.
  2. Find “// readOneProduct will be here” and replace it with the following code.
// read one product
factory.readOneProduct = function(id){
	return $http({
		method: 'GET',
		url: 'http://localhost/api/product/read_one.php?id=' + id
	});
};

// updateProduct will be here

7.5 Output

You should see a “read one” button in the product list. Once user clicks this, a dialog box will appear with a product information.

8.0 How To Update Data Using AngularJS?

8.1 Put “Edit” button in products list

  1. Open “read_products.template.html” file.
  2. Find
    <!-- 'edit' button will be here -->

    and replace it with the following code.

<md-button class="md-raised md-primary" ng-click="showUpdateProductForm(product.id)">Edit</md-button>

8.2 Show editable product information in dialog box

  1. Open “products.controller.js” file.
  2. Find “// showUpdateProductForm will be here” and replace it with the following code.
// retrieve record to fill out the form
$scope.showUpdateProductForm = function(id){

	// get product to be edited
	productsFactory.readOneProduct(id).then(function successCallback(response){

		// put the values in form
		$scope.id = response.data.id;
		$scope.name = response.data.name;
		$scope.description = response.data.description;
		$scope.price = response.data.price;

		$mdDialog.show({
			controller: DialogController,
			templateUrl: './app/products/update_product.template.html',
			parent: angular.element(document.body),
			targetEvent: event,
			clickOutsideToClose: true,
			scope: $scope,
			preserveScope: true,
			fullscreen: true
		}).then(
			function(){},

			// user clicked 'Cancel'
			function() {
				// clear modal content
				$scope.clearProductForm();
			}
		);

	}, function errorCallback(response){
		$scope.showToast("Unable to retrieve record.");
	});

}

// updateProduct will be here

8.3 Create “update_product.template.html” file

The dialog box need an HTML template with product information.

  1. Open “products” folder.
  2. Inside “products” folder, create “update_product.template.html” file and place the following code.
<md-dialog>
    <form ng-cloak>

        <!-- dialog box title -->
        <md-toolbar>
            <div class="md-toolbar-tools">
                <h2>Update Product</h2>
            </div>
        </md-toolbar>

        <md-dialog-content>
            <div class="md-dialog-content">

                <!-- dialog box input fields with editable product information -->
                <md-input-container class="md-block">
                    <label>Name</label>
                    <input ng-model="name">
                </md-input-container>

                <md-input-container class="md-block">
                    <label>Description</label>
                    <input ng-model="description">
                </md-input-container>

                <md-input-container class="md-block">
                    <label>Price</label>
                    <input ng-model="price">
                </md-input-container>

            </div>
        </md-dialog-content>

        <!-- dialog box buttons -->
        <md-dialog-actions layout="row">
            <md-button ng-click="cancel()">Cancel</md-button>
            <md-button ng-click="updateProduct()" class="md-primary">Update</md-button>
        </md-dialog-actions>
    </form>
</md-dialog>

8.4 Put “updateProduct” method in controller

If the user click the “update” button in the dialog box, we will send the udpated data to the API.

  1. Open “products.controller.js” file.
  2. Find “// updateProduct will be here” and replace it with the following code.
// update product record / save changes
$scope.updateProduct = function(){

	productsFactory.updateProduct($scope).then(function successCallback(response){

		// tell the user product record was updated
		$scope.showToast(response.data.message);

		// refresh the product list
		$scope.readProducts();

		// close dialog
		$scope.cancel();

		// clear modal content
		$scope.clearProductForm();

	},
	function errorCallback(response) {
		$scope.showToast("Unable to update record.");
	});

}

// confirmDeleteProduct will be here

8.5 Put “updateProduct” method in factory

The factory will help us send data to API.

  1. Open “products.factory.js” file.
  2. Find “// updateProduct will be here” and replace it with the following code.
// update product
factory.updateProduct = function($scope){

	return $http({
		method: 'POST',
		data: {
			'id' : $scope.id,
			'name' : $scope.name,
			'description' : $scope.description,
			'price' : $scope.price,
			'category_id' : 1
		},
		url: 'http://localhost/api/product/update.php'
	});
};

// deleteProduct will be here

8.6 Output

You should see the “Edit” button in the products list. When this button is clicked, a dialog box with “udpate product” form will appear.

The form contains the editable product information.

9.0 How To Delete Data Using AngularJS?

9.1 Put “delete” button in products list

  1. Open “read_products.template.html” file.
  2. Find
    <!-- 'delete' button will be here -->

    and replace it with the following code.

<md-button class="md-raised md-danger" ng-click="confirmDeleteProduct($event, product.id)">Delete</md-button>

9.2 Ask user to confirm product deletion

  1. Open “products.controller.js” file.
  2. Find “// confirmDeleteProduct will be here” and replace it with the following code.
// cofirm product deletion
$scope.confirmDeleteProduct = function(event, id){

	// set id of record to delete
	$scope.id = id;

	// dialog settings
	var confirm = $mdDialog.confirm()
		.title('Are you sure?')
		.textContent('Product will be deleted.')
		.targetEvent(event)
		.ok('Yes')
		.cancel('No');

	// show dialog
	$mdDialog.show(confirm).then(
		// 'Yes' button
		function() {
			// if user clicked 'Yes', delete product record
			$scope.deleteProduct();
		},

		// 'No' button
		function() {
			// hide dialog
		}
	);
}

9.3 Put “deleteProduct” function in controller

If the user click the ‘Yes’ button, our app will delete the record.

Place the following code after the previous section’s code.

// delete product
$scope.deleteProduct = function(){

	productsFactory.deleteProduct($scope.id).then(function successCallback(response){

		// tell the user product was deleted
		$scope.showToast(response.data.message);

		// refresh the list
		$scope.readProducts();

	}, function errorCallback(response){
		$scope.showToast("Unable to delete record.");
	});

}

// searchProducts will be here

9.4 Put “deleteProduct” function in factory

The factory will help us send data to API.

  1. Open “products.factory.js” file.
  2. Find “// deleteProduct will be here” and replace it with the following code.
// delete product
factory.deleteProduct = function(id){
	return $http({
		method: 'POST',
		data: { 'id' : id },
		url: 'http://localhost/api/product/delete.php'
	});
};

// searchProducts will be here

9.5 Output

You should see the “Delete” button in products list. When a user click this button, a dialog box will appear asking the confirmation to delete the record.

10.0 How To Search Data Using AngularJS?

This feature is part of LEVEL 2 source code. We did not use “filter” to search product records. We search the records with the help of API.

10.1 Allow users to type search keywords

  1. Open “read_products.template.html” file.
  2. Find
    <!-- 'search' bar will be here -->

    and replace it with the following code.

<!-- used for searching products in api -->
<md-input-container class="md-block m-b-0px">
	<form ng-submit="searchProducts()">
		<label>Search products...</label>
		<input ng-model="product_search_keywords">
	</form>
</md-input-container>

10.2 Add “searchProducts” function in controller

  1. Open “products.controller.js” file.
  2. Find “// searchProducts will be here” and replace it with the following code.
// search products
$scope.searchProducts = function(){

	// use products factory
	productsFactory.searchProducts($scope.product_search_keywords).then(function successCallback(response){
		$scope.products = response.data.records;
	}, function errorCallback(response){
		$scope.showToast("Unable to read record.");
	});
}

10.3 Add “searchProducts” function in factory

The factory will help us read records based on search keywords.

  1. Open “products.factory.js” file.
  2. Find “// searchProducts will be here” and replace it with the following code.
// search all products
factory.searchProducts = function(keywords){
	return $http({
		method: 'GET',
		url: 'http://localhost/api/product/search.php?s=' + keywords
	});
};

10.4 Output

You should see the “search” bar above products list. Once user type a keyword and press the “enter” key, search results must be seen.

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 files to your server directory.
  2. Set up the “api” by following the README.txt inside the “api” folder.
  3. Open your browser and run index.html
  4. If you can see the list of products, it means your set up is correct.

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
Angular Material UI YES
PHP REST API source code YES
FREE email support for 3 months YES
Source code updates via email YES
Download Now

13.0 Download LEVEL 2 Source Code

FEATURES LEVEL 2
All features of LEVEL 1 YES
Search products YES
Pagination of products & search products YES
Create category YES
Read category YES
Read one category YES
Update category YES
Delete category YES
Search categories YES
Pagination of categories & search categories YES
Navigation bar YES
Use of AngularJS Directives YES
Use of AngularJS $q.all() YES
Use of AngularJS MainController YES
Use of Single pagination template File YES
Use of ng-class in navigation bar YES
FREE email support for 6 months YES
Download Now

14.0 Download ALL LEVELS

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

Download Now

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 AngularJS 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?

Learn more JavaScript programming with our Angular 2 CRUD Tutorial – Step By Step Guide!

16.0 Related Tutorials

17.0 Some 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!

Thanks for reading our AngularJS CRUD Example with Material Design – Step by Step Guide!

Home JavaScript

AJAX CRUD Tutorial Using jQuery, JSON and PHP – Step by Step Guide!


Previously, we learned how to create a simple REST API in PHP. Today, we are going to learn how to create or insert, read, update and delete records with our AJAX CRUD Tutorial. We will use jQuery, JSON and PHP.

Contents of this tutorial include: Read more

Home JavaScript

Move Options Between Two Select Boxes

Today we are going to do a code that can move options between two select boxes and save the changes to the database. I think this functionality will improve the user experience since the interface is intuitive.

In this example, we are going to have the first select box (left side) which contains the list or data of available objects, the buttons that will make the options move either to the left or right, the second select box (right side) which contains the list of assigned objects, and of course, the save button.

See my video demo here:

assigned_objects table – this will be used to store the ids of assigned objects.

CREATE TABLE IF NOT EXISTS `assigned_objects` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `type` int(11) NOT NULL COMMENT ‘1=user,2=location’,
  `object_id` int(11) NOT NULL,
  PRIMARY KEY (`id`)
)

locations table – this will be used to store the location objects

—
— Table structure for table `locations`
—
CREATE TABLE IF NOT EXISTS `locations` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(64) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB  DEFAULT CHARSET=latin1 AUTO_INCREMENT=11 ;

—
— Dumping data for table `locations`
—

INSERT INTO `locations` (`id`, `name`) VALUES
(1, ‘Cavite’),
(2, ‘Laguna’),
(3, ‘Batangas’),
(4, ‘Rizal’),
(5, ‘Quezon’),
(6, ‘Antiipolo’),
(7, ‘Capiz’),
(8, ‘Boracay’),
(9, ‘Mindoro’),
(10, ‘Novaliches’);

Our index.php code:

<html>
    <head>
        <title>Move Options Between Two Select Boxes And Save Changes To Database</title>
        <!– include some style –>
        <link rel=”stylesheet” type=”text/css” href=”css/style.css” />
    </head>
<body>
<?php
//connect to database
include ‘db_connect.php’;

//if the form was submitted
if( $_POST ){

    //delete previously assigned locations
    //in this example, type = 2 means “location”
    $sql = “delete from assigned_objects where type = 2”;
    
    //execute the sql
    if( $mysqli->query( $sql ) ){
    
        //if the query was executed successfully
        //save newly assigned names
        //$_POST[‘location_right’] is the select box on the right side
        foreach( $_POST[‘location_right’] as $value ){
            
            //write save query
            $sql = “insert into assigned_objects ( type, object_id ) 
                        values( 2, “ . $mysqli->real_escape_string( $value ) . ” )”;

            //execute save sql query
            if( !( $mysqli->query( $sql ) ) ){
                
                //if the query execution was unsuccessful
                echo “<div>Database Error: Unable to insert record.</div>”;
            }
            
        }
        
    }else{
        //if unable to delete previously assigned locations
        echo “<div>Database Error: Unable to delete assigned locations.</div>”;
    }
    
}

//get ids of currently assigned locations 
$sql = “select * from assigned_objects where type = 2”;
$result = $mysqli->query( $sql );

if( $result ){
    
    //$location_in will be our variable to accumulate currently assigned locations ids
    //example value will be “46, 49, 51”, 
    //which will be used to exempt currently assigned locations (right select box) 
    //to available locations list (left select box)
    $location_in = “”;
    
    //get number of rows found
    $num = $result->num_rows;
    
    if( $num ){ //if there are assigned locations in the database
    
        //set $x to 1, the first loop
        $x = 1;
        
        while( $row = $result->fetch_assoc() ){ //loop the accumulate values
        
            //object_id is actually the location id
            $location_in .= $row[‘object_id’];
            
            //when $x is less than the total number of rows, append a comma
            //else, do not append a comma
            if( $x < $num ){
                $location_in .= “, “;
            }
            
            //increment $x
            $x++;
        }
        
    }

}else{
    //when there’s an error selecting the assigned locations
    echo “Database Error: Unable to select assigned locations.”;
}

?>

<div>

<!–
    here on our form, the onsubmit value is very important,
    it will select all the values in the location_right select box,
    which is to be saved in the database.
    see the javascript section for details about selectAll()
–>
<form action=’index.php’ method=’post’ onsubmit=”return selectAll( new Array( ‘location_right’ ) );”>

    <!– left select box –>
    <div class=’select_box’>
        <div class=’select_title’>Available Locations</div>
        <div style=’clear:both;’></div>
        <select name=’location_left’ id=’location_left’ size=’7′ multiple=’multiple’>
            <?php
            
            if( $location_in ){ //if $location_id has a value, there are location ids to be exempted
                $sql = “select * from locations where id not in ( {$location_in} ) order by name”; 
            }else{
                //else, select all locations
                $sql = “select * from locations”; 
            }
            
            $result = $mysqli->query( $sql );

            if( $result ){
                //if it returns a result, loop through it with options tag
                while( $row = $result->fetch_assoc() ){
                    echo “<option value=’{$row[‘id’]}‘>{$row[‘name’]}</option>”;
                }
            }
            ?>
        </select>
    </div>

    <!– direction move buttons –>
    <div class=’btn’>
        <!– option move to right button –>
        <button type=”button” onclick=”move( ‘location_left’, ‘location_right’ )”> > </button>
        <br />
        <!– option move to left button –>
        <button type=”button” onclick=”move( ‘location_right’, ‘location_left’ )”> < </button>
    </div>

    <!– right select box –>
    <div class=’select_box’>
        <div class=’select_title’>Assigned Locations</div>
        <div style=’clear:both;’></div>
        <select name=’location_right[]’ id=’location_right’ size=’7′ multiple=’multiple’>
        
            <?php       
            //query joining assigned_objects and locations table
            //so we can easily get the location_name
            $sql = “select
                        l.id as location_id, 
                        l.name as location_name 
                    from 
                        assigned_objects ao, locations l
                    where 
                        ao.type = 2 
                        and ao.object_id in ( {$location_in} )
                        and ao.object_id = l.id”;
                    
            $result = $mysqli->query( $sql );

            if( $result ){
                //if query successful, loop through the values with option tag
                //so it will show up in the select list
                while( $row = $result->fetch_assoc() ){
                    
                    echo “<option value=’{$row[‘location_id’]}‘>{$row[‘location_name’]}</option>”;
                
                }
            }
            
            ?>
        </select>
        
    </div>
    
    <div style=’clear:both;’></div>
    <input type=’submit’ value=’Save’ />
    
</form>

<script type=’text/javascript’>
//this function will select all the values of the right select box, so you can post it
//this function can accept array of select boxes with id as its reference
function selectAll( obj_arr ){

    var obj_sel;
    for ( var i = 0; i < obj_arr.length; i++ ){
    
        obj_sel = document.getElementById( obj_arr[i] );
        
        for( var j = 0; j < obj_sel.options.length; j++ ){
            obj_sel.options[j].selected = true;
        }
        
    }
    
}

function move( id_1, id_2 ){
        
        //the box where the value will come from
        var opt_obj = document.getElementById( id_1 );
        
        //the box where the value will be locationd
        var sel_obj = document.getElementById( id_2 );
        
        for ( var i = 0; i < opt_obj.options.length; i++ ){ //loop to check for multiple selections
                
                if ( opt_obj.options[i].selected == true ){ //check if the option was selected
                        
                        //value to be transfered
                        var selected_text = opt_obj.options[i].text;
                        var selected_value = opt_obj.options[i].value;
                        
                        //remove from opt
                        opt_obj.remove( i );
                        
                        //decrease value of i since an option was removed 
                        //therefore the opt_obj.options.length will also decrease
                        i–;
                        
                        //process to sel
                        var new_option_index = sel_obj.options.length;
                        sel_obj.options[new_option_index] = new Option( selected_text, selected_value );
                        
                }
                
        }
}
        
</script>

</body>
</html>

I have another example here that uses two objects which are users and locations. See my video demo:

users table – this will be used to store the user objects.

—
— Table structure for table `users`
—
CREATE TABLE IF NOT EXISTS `users` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `firstname` varchar(32) NOT NULL,
  `lastname` varchar(32) NOT NULL,
  `email` varchar(32) NOT NULL,
  `username` varchar(32) NOT NULL,
  `password` varchar(32) NOT NULL,
  `modified` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB  DEFAULT CHARSET=latin1 AUTO_INCREMENT=55 ;

—
— Dumping data for table `users`
—

INSERT INTO `users` (`id`, `firstname`, `lastname`, `email`, `username`, `password`, `modified`) VALUES
(28, ‘John’, ‘Dalisay’, ”, ‘john’, ‘john123’, ‘2012-01-15 15:26:14’),
(39, ‘Jemski’, ‘Panlilios’, ‘jemboy@gmail.com’, ‘jemboy09’, ‘jem123’, ‘2012-03-17 23:20:05’),
(40, ‘Darwin’, ‘Dalisay’, ”, ‘dada08’, ‘dada123’, ‘2012-01-15 15:25:34’),
(46, ‘Jaylord’, ‘Bitamug’, ”, ‘jayjay’, ‘jay123’, ‘2012-01-15 15:27:04’),
(49, ‘Justine’, ‘Bongola’, ”, ‘jaja’, ‘jaja123’, ‘2012-01-15 15:27:21’),
(50, ‘Jun’, ‘Sabayton’, ”, ‘jun’, ‘jun123’, ‘2012-02-05 18:15:14’),
(51, ‘Lourd’, ‘De Veyra’, ”, ‘lourd’, ‘lourd123’, ‘2012-02-05 18:15:36’),
(52, ‘Asi’, ‘Taulava’, ”, ‘asi’, ‘asi123’, ‘2012-02-05 18:15:58’),
(53, ‘James’, ‘Yap’, ”, ‘james’, ‘jame123’, ‘2012-02-05 18:16:17’),
(54, ‘Chris’, ‘Tiu’, ”, ‘chris’, ‘chris123’, ‘2012-04-11 17:16:29’);

The code download is included in the download link above of this post. I have written this code few years ago with MySQL, but you can easily convert it to MySQLi or PDO though. Here’s the mysql_index.php code:

<html>
        <head>
                <title>Move Options Between Two Select Boxes</title>
                
                <style type=’text/css’>
                        select{
                                width:200px;
                        }
                        
                        .select_box{
                                float:left;
                                margin:0 0 20px 0;
                        }
                        
                        .btn{
                                float:left;
                                margin:20px;
                        }
                </style>
        </head>
<body>
<?php
//connect to database
include ‘mysql_db_connect.php’;

if( $_POST ){

    //delete previously assigned names
    $sql = “delete from assigned_objects where type = 1”;
    mysql_query( $sql );
    
    //save newly assigned names
    foreach( $_POST[‘name_right’] as $value ){
        
        $sql = “insert into assigned_objects ( type, object_id ) values( 1, {$value} )”;
        mysql_query( $sql );
        
    }
    
    //delete previously assigned locations
    $sql = “delete from assigned_objects where type = 2”;
    mysql_query( $sql );
    
    //save newly assigned locations
    foreach( $_POST[‘location_right’] as $value ){
        
        $sql = “insert into assigned_objects ( type, object_id ) values( 2, {$value} )”;
        mysql_query( $sql );
        
    }
    
}

//(name) prepare id values for IN
$sql = “select * from assigned_objects where type = 1”;
$rs = mysql_query( $sql );

$in = “”;
$x = 1;
$num = mysql_num_rows( $rs );

if( $num ){
    while( $row = mysql_fetch_array( $rs ) ){
        extract( $row );
        $in .= $object_id;
        
        if( $x < $num ){
            $in .= “, “;
        }
        
        $x++;
    }
}

//(location) prepare id values for IN
$sql = “select * from assigned_objects where type = 2”;
$rs = mysql_query( $sql );

$location_in = “”;
$x = 1;
$num = mysql_num_rows( $rs );

if( $num ){
    while( $row = mysql_fetch_array( $rs ) ){
        extract( $row );
        $location_in .= $object_id;
        
        if( $x < $num ){
            $location_in .= “, “;
        }
        
        $x++;
    }
}
?>

<!–
    here on our form, the onsubmit value is very important,
    it will select all the values in the location_right select box,
    which is to be saved in the database.
    see the javascript section for details about selectAll()
–>
<form action=’#’ method=’post’ onsubmit=”return selectAll( new Array( ‘name_right’, ‘location_right’ ) );”>

    <!– left select box –>
    <div class=’select_box’>
        <div class=’select_title’>Available Users</div>
        <div style=’clear:both;’></div>
        <select name=’name_left’ id=’name_left’ size=’7′ multiple=’multiple’>
        
            <?php
            
            if( $in ){ //if $in has a value, there are location ids to be exempted
                $sql = “select * from users where id not in ( {$in} ) order by firstname”; 
            }else{
                //else select all users
                $sql = “select * from users”; 
            }
            
            $rs = mysql_query( $sql );
            
            while( $row = mysql_fetch_array( $rs ) ){
                extract( $row );
                echo “<option value=’{$id}‘>{$firstname} {$lastname}</option>”;
            }
            
            ?>
        </select>
    </div>

        <!– direction move buttons –>
        <div class=’btn’>
            <!– move to right button –>
            <button type=”button” onclick=”move( ‘name_left’, ‘name_right’ )”> > </button>
            <br />
            <!– move to left button –>
            <button type=”button” onclick=”move( ‘name_right’, ‘name_left’ )”> < </button>
        </div>

    <!– right select box –>
    <div class=’select_box’>
        <div class=’select_title’>Assigned Users</div>
        <div style=’clear:both;’></div>
        <select name=’name_right[]’ id=’name_right’ size=’7′ multiple=’multiple’>
        
            <?php       
            
            $sql = “select
                        u.id as user_id, 
                        u.firstname as fn,
                        u.lastname as ln
                    from 
                        assigned_objects ao, users u
                    where 
                        ao.type = 1
                        and ao.object_id in ( {$in} )
                        and ao.object_id = u.id”;
            $rs = mysql_query( $sql );
            
            while( $row = mysql_fetch_array( $rs ) ){
                
                echo “<option value=’{$row[‘user_id’]}‘>{$row[‘fn’]} {$row[‘ln’]}</option>”;
                
            }
            
            ?>
        </select>
        
    </div>

    <div style=’clear:both;’></div>

    <!– left select box –>
    <div class=’select_box’>
        <div class=’select_title’>Available Locations</div>
        <div style=’clear:both;’></div>
        <select name=’location_left’ id=’location_left’ size=’7′ multiple=’multiple’>
            <?php
            
            if( $location_in ){
                $sql = “select * from locations where id not in ( {$location_in} ) order by name”; 
            }else{
                $sql = “select * from locations”; 
            }
            
            $rs = mysql_query( $sql );
            
            while( $row = mysql_fetch_array( $rs ) ){
                extract( $row );
                echo “<option value=’{$row[‘id’]}‘>{$row[‘name’]}</option>”;
            }
            
            ?>
        </select>
    </div>

        <!– direction move buttons –>
        <div class=’btn’>
            <!– move to right button –>
            <button type=”button” onclick=”move( ‘location_left’, ‘location_right’ )”> > </button>
            <br />
            <!– move to left button –>
            <button type=”button” onclick=”move( ‘location_right’, ‘location_left’ )”> < </button>
        </div>

    <!– right select box –>
    <div class=’select_box’>
        <div class=’select_title’>Assigned Locations</div>
        <div style=’clear:both;’></div>
        <select name=’location_right[]’ id=’location_right’ size=’7′ multiple=’multiple’>
        
            <?php       
            $sql = “select
                        l.id as location_id, 
                        l.name as location_name 
                    from 
                        assigned_objects ao, locations l
                    where 
                        ao.type = 2 
                        and ao.object_id in ( {$location_in} )
                        and ao.object_id = l.id”;
            $rs = mysql_query( $sql );
            
            while( $row = mysql_fetch_array( $rs ) ){
                
                echo “<option value=’{$row[‘location_id’]}‘>{$row[‘location_name’]}</option>”;
                
            }
            
            ?>
            
        </select>
    </div>
    
    <div style=’clear:both;’></div>
    <input type=’submit’ value=’Save’ />
        
</form>

<script type=’text/javascript’>

function selectAll( obj_arr ){

    var obj_sel;
    for ( var i = 0; i < obj_arr.length; i++ ){
    
        obj_sel = document.getElementById( obj_arr[i] );
        
        for( var j = 0; j < obj_sel.options.length; j++ ){
            obj_sel.options[j].selected = true;
        }
        
    }
    
}

function move( id_1, id_2 ){
        
        //the box where the value will come from
        var opt_obj = document.getElementById( id_1 );
        
        //the box where the value will be locationd
        var sel_obj = document.getElementById( id_2 );
        
        for ( var i = 0; i < opt_obj.options.length; i++ ){ //loop to check for multiple selections
                
                if ( opt_obj.options[i].selected == true ){ //check if the option was selected
                        
                        //value to be transfered
                        var selected_text = opt_obj.options[i].text;
                        var selected_value = opt_obj.options[i].value;
                        
                        //remove from opt
                        opt_obj.remove( i );
                        
                        //decrease value of i since an option was removed 
                        //therefore the opt_obj.options.length will also decrease
                        i–;
                        
                        //process to sel
                        var new_option_index = sel_obj.options.length;
                        sel_obj.options[new_option_index] = new Option( selected_text, selected_value );
                        
                }
                
        }
}
        
</script>

</body>
</html>

If you have many object types stored in your database, you have to use a loop to generate the pair of select boxes and buttons.

Download Source Code

You can download all the code used in this tutorial for only $9.99 $5.55!

Thank you for learning from our post about: Move Options Between Two Select Boxes.

Home JavaScript

How To Use Vertical TinyDropdown 2

Hi guys, today I wanna share to you the code I tweaked with this amazing multi-level JavaScript Dropdown Menu by Scriptiny. In my opinion, it looks fast, smooth and clean. The hover animation is really nice. I love it.

But there’s a problem. The script provided by Scriptiny is for horizontal dropdown menu only (as you can see in the picture above). But I needed it to be a vertical dropdown menu like some people were asking about. I’m gonna show you the example code I tweaked to make this a vertical dropdown menu.

Our index.html code looks like the following.

<!DOCTYPE html PUBLIC “-//W3C//DTD XHTML 1.0 Transitional//EN” “http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd”>
<html xmlns=“http://www.w3.org/1999/xhtml”>
    <head>
        <meta http-equiv=“Content-Type” content=“text/html; charset=iso-8859-1” />
        <title>TinyDropdown 2 Vertical Version</title>
        
        <link rel=“stylesheet” href=“tinydropdown.css” type=“text/css” />
        <script type=“text/javascript” src=“tinydropdown.js”></script>
        
    </head>
<body>
    
    
<div class=“nav”>
    <ul id=“menu” class=“menu”>
        <li>
            <span>One</span>
            <ul style=‘top: 0; margin-left: 170px;’>
                <li><a href=“#”>One</a></li>
                <li><a href=“#”>Two</a></li>
                <li><a href=“#”>Three</a></li>  
                <li><a href=“#”>Four</a></li>
            </ul>
        </li>
        
        <li>
            <span>Two</span>
            <ul style=‘top: 0; margin-left: 170px;’>
            
                <li>
                    <a href=“#”>One</a>
                    <ul>
                        <li><a href=“#”>One</a></li>
                        <li><a href=“#”>Two</a>
                            <ul>
                                <li><a href=“#”>One</a></li>
                            </ul>
                        </li>
                    </ul>
                </li>
                
                <li><a href=“#”>Two</a></li>
                
            </ul>
        </li>
        
        <li>
            <span>Three</span>
            <ul style=‘top: 0; margin-left: 170px;’>
                <li><a href=“#”>One</a></li>
                <li><a href=“#”>Two</a></li>
            </ul>
        </li>
        <li>
            <span>Four</span>
            <ul style=‘top: 0; margin-left: 170px;’>
                <li><a href=“#”>One</a></li>
                <li><a href=“#”>Two</a></li>
            </ul>
        </li>
        <li>
            <span><a href=‘#’>Five</a></span>
        </li>
        
    </ul>
</div>
<script type=“text/javascript”>
    var dropdown=new TINY.dropdown.init(“dropdown”, {id:’menu’, active:’menuhover’});
</script>

</body>
</html>

Our tinydropdown.css code:

*{
    margin:0; 
    padding:0; 
    outline:0;
}
.nav {
    height:auto; 
    width: 170px; 
    float:left; 
    background:#aaa; 
    color:#fff; 
    /*text-shadow:1px 1px #888; */
    z-index:1000;
}

.menu a {
    color:#fff; 
    text-decoration:none; 
    width:170px; 
    height:auto; 
    display:block;
}

.menu span {
    color:#fff; 
    text-decoration:none; 
    width:170px; 
    height:auto; 
    font-weight:bold;
    display:block;
}

.menu a:hover {
    color:#fff; 
    height:auto; 
    background:#999;
    display:block;
    height:auto;
    width:170px;
}

.menu {
    list-style:none; 
    font:16px Arial,Verdana; 
    text-align:center; 
    width:600px; 
    margin:0 auto;
}

.menu li {
    position:relative;
    width:170px; 
    z-index:1000;
    height:auto; 
    line-height:30px;
    background:#AAAAAA;
    /*line-height:28px; this is responsible for line height*/
    border-bottom:thin solid #fff;
    
}

.menu ul {
    display:none; 
    position:absolute; 
    font:normal 16px Arial,Verdana; 
    top:36px; 
    left:0; 
    background:#aaa; 
    display:none; 
    list-style:none;
}

.menu ul li {
    float:none; 
    width:170px;
    display:block;
}

.menu ul li a, li.menuhover li a, li.menuhover li.menuhover li a {
    float:none; 
    display:block; 
    background:none; 
    height:auto; 
    
    width:170px;
    display:block;
    
}

.menu ul li a:hover, li.menuhover li a:hover, li.menuhover li.menuhover li a:hover {
    background:#999; 
    color:#fff;
    height:auto; 
    
    width:170px;
    display:block;
    
}

.menu ul li span, li.menuhover li span, li.menuhover li.menuhover li span {
    float:none; 
    display:block; 
    background:none; 
    height:auto; 
    
    
    width:170px;
}

.menu ul ul {
    left:170px; 
    top:0;
}
.menu li.submenu {
    
}

.menu li.noborder {
    border-top:none;
}

li.menuhover a, li.menuhover li.menuhover a {
    color:#fff; 
    background:#999; 
    height:auto; 
    
    width:170px;
    display:block;
    
}

li.menuhover span, li.menuhover li.menuhover span {
    color:#fff; 
    background:#999;
    height:auto; 
    
    width:170px;
    display:block;
    
}

#info {
    width:180px; 
    background:#eee;
}

#info li {
    width:160px; 
    border-top:none; 
    padding:8px 10px; 
    color:#666; 
    /*text-shadow:1px 1px #fff; */
    text-align:left;
}

Our tinydropdown.js code:

var TINY={};
function T$(i){return document.getElementById(i)}
function T$$(e,p){return p.getElementsByTagName(e)}

TINY.dropdown=function(){
    var p={fade:1,slide:1,active:0,timeout:200}, init=function(n,o){
        for(s in o){p[s]=o[s]} p.n=n; this.build()
    };
    init.prototype.build=function(){
        this.h=[]; this.c=[]; this.z=1000;
        var s=T$$(‘ul’,T$(p.id)), l=s.length, i=0; p.speed=p.speed?p.speed*.1:.5;
        for(i;i<l;i++){
            var h=s[i].parentNode; this.h[i]=h; this.c[i]=s[i];
            h.onmouseover=new Function(p.n+‘.show(‘+i+‘,1)’);
            h.onmouseout=new Function(p.n+‘.show(‘+i+‘)’)
        }
    };
    init.prototype.show=function(x,d){
        var c=this.c[x], h=this.h[x];
        clearInterval(c.t); clearInterval(c.i); c.style.overflow=‘hidden’;
        if(d){
            if(p.active&&h.className.indexOf(p.active)==-1){h.className+=‘ ‘+p.active}
            if(p.fade||p.slide){
                c.style.display=‘block’;
                if(!c.m){
                    if(p.slide){
                        c.style.visibility=‘hidden’; c.m=c.offsetHeight; c.style.height=‘0’; c.style.visibility=”
                    }else{
                        c.m=100; c.style.opacity=0; c.style.filter=‘alpha(opacity=0)’
                    }
                    c.v=0
                }
                if(p.slide){
                    if(c.m==c.v){
                        c.style.overflow=‘visible’
                    }else{
                        c.style.zIndex=this.z; this.z++; c.i=setInterval(function(){slide(c,c.m,1)},20)
                    }
                }else{
                    c.style.zIndex=this.z; this.z++; c.i=setInterval(function(){slide(c,c.m,1)},20)
                }
            }else{
                c.style.zIndex=this.z; c.style.display=‘block’
            }
        }else{
            c.t=setTimeout(function(){hide(c,p.fade||p.slide?1:0,h,p.active)},p.timeout)
        }
    };
    function hide(c,t,h,s){
        if(s){h.className=h.className.replace(s,”)}
        if(t){c.i=setInterval(function(){slide(c,0,-1)},20)}else{c.style.display=‘none’}
    }
    function slide(c,t,d){
        if(c.v==t){
            clearInterval(c.i); c.i=0;
            if(d==1){
                if(p.fade){c.style.filter=”; c.style.opacity=1}
                c.style.overflow=‘visible’
            }
        }else{
            c.v=(t–Math.floor(Math.abs(t–c.v)*p.speed)*d);
            if(p.slide){c.style.height=c.v+‘px’}
            if(p.fade){var o=c.v/c.m; c.style.opacity=o; c.style.filter=‘alpha(opacity=’+(o*100)+‘)’}
        }
    }
    return{init:init}
}();

The output of the codes above will look like this:

Also, if you want my version of its horizontal dropdown menu, output looks like this:

Download Source Code

You can download all the code used in this tutorial for only $9.99 $5.55!

Thank you for learning from our post about: How To Use Vertical TinyDropdown 2.

Home JavaScript

Sample Use of JavaScript OnFocus and OnBlur Event

You can see this example on many sites today such as yahoomail.

When you click on the search box, the word “Search” will gone. When you click on other part of the webpage, the word “Search” comes back in it.

HOW TOs.

Step 1: Create your index.html file and put the following codes:

<html>
     <head>
          <title>Sample Use of JavaScript OnFocus and OnBlur Event</title>
     </head>
<body>
     <input type="text" value="Type keywords here..." size="40"
       OnFocus="if(this.value=='Type keywords here...') this.value='';"
       OnBlur="if(this.value=='') this.value = 'Type keywords here...';" />
</body>
</html>

TIPs

This thing is used often in search boxes. You will save webpage space ‘coz you won’t have to put a label “Search” before the search box

Download Source Code

You can download all the code used in this tutorial for only $5 $1!

Thank you for reading! Belated Merry Christmas and Advanced Happy New Year Everyone! :)