Posts

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 PHP

PHP OOP CRUD Tutorial – Step By Step Guide!


Previously, we learned how to create or insert, read, update and delete database records with our PHP and MySQL CRUD tutorial for beginners. This time, we will learn object-oriented programming with PHP & MySQL.

This post will include the following contents: Read more

Home PHP

PHP CRUD Tutorial for Beginners – Step By Step Guide!

Previously, we learned how to run your first PHP script. This time, we we learn CRUD operations with PHP and MySQL. CRUD stands for Create, Read, Update and Delete database records.

This tutorial is for your if:

  • You need a high quality and updated reference for a PHP CRUD tutorial.
  • You need to learn how to do CRUD operations with PHP and MySQL.
  • You a beginner in this kind of PHP web programming.

Coding CRUD with PHP and MySQL is one of the basics. PHP web programmers must be able to code it with less effort. We can perform this task using any of the three PHP Database extensions:

  1. Using the MySQL extension.
  2. Using the MySQLi extension.
  3. Using the PDO extension.

PHP 5.5 deprecated the MySQL extension. It is not recommended to use these days.

If you are programming with PHP, you’ll have to use either MySQLi (i means improved) or PDO extension.

With that in mind, we will use the PDO extension. It is the newest and actively developed way of programming these CRUD grids.

What will you learn? We will cover the following topics or contents.

1.0 Program Output
2.0 File Structure

3.0 Prepare The Database
3.1 Create the Database
3.2 Create the Database Table
3.3 Dump Sample Data On The Table
3.4 Create Database Connection PHP File

4.0 Create or Insert Record in PHP
4.1 HTML5 Boilerplate For create.php
4.2 HTML Form To Input New Record Data
4.3 Code Create A New Record

5.0 Read Records in PHP
5.1 Basic HTML Code For index.php
5.2 Read Records From The Database

6.0 Read One Record in PHP
6.1 Basic HTML Code For read_one.php
6.2 Read Records From The Database
6.3 Display Record Details

7.0 Update Record in PHP
7.1 Basic HTML Code For update.php
7.2 Read A Record By ID Parameter
7.3 HTML Form To Update A Record
7.4 Code To Update The Record

8.0 Delete Record in PHP
8.1 Tell The User If Record Was Deleted
8.2 JavaScript To Verify Record Deletion
8.3 Delete Record From The Database

9.0 Pagination in PHP
9.1 Set Pagination Variables
9.2 Add LIMIT Clause in SELECT Query
9.3 Count Total Number Of Records
9.4 Include Paging File
9.5 Create paging.php

10.0 File Upload in PHP
10.1 Add HTML “file” field
10.2 Add “image” field
10.3 Set variables for file upload
10.4 Make sure submitted file is a real image
10.5 Make sure certain file types are allowed
10.6 Make sure file does not exist
10.7 make sure submitted file is not too large
10.8 Make sure the ‘uploads’ folder exists
10.9 Try to upload the file
10.10 Show image in “read one” page

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 LEVEL 3 Source Code
15.0 Download ALL LEVELS

16.0 Online Resources
17.0 What’s Next?
18.0 Related Tutorials
19.0 Notes

1.0 PHP CRUD Tutorial Program Output

We usually have three LEVELS of source code output. But WHY? Because I believe in "Learning Progression" to ensure efficient learning. Learn more

Below are some screenshots of our script’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.

Please note that the following images are just output previews. New features might be added already the time you are reading this.

1.1 LEVEL 1 Source Code Output


1.2 LEVEL 2 Source Code Output


1.3 LEVEL 3 Source Code Output


The LEVEL 2 and LEVEL 3 source code outputs 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 Project File Structure

Our PHP CRUD tutorial will contain the following main files.

  • dev/products.sql – contains the database table structure and sample data used in this project. Once you created your database in PhpMyAdmin, you can import this file.
  • libs/ – is where our Bootstrap CSS framework and jQuery library is located.
  • config/database.php – used for database connection and configuration.
  • create.php – used for creating a new record. It contains an HTML form where the user can enter details for a new record.
  • index.php – used for reading records from the database. It uses an HTML table to display the data retrieved from the MySQL database.
  • read_one.php – used for reading one or single record from database. It uses an HTML table to display the data retrieved from the MySQL database.
  • update.php – used for updating a record. It uses an HTML form which will be filled out with data based on the given “id” parameter.
  • delete.php – used for deleting a record. It accepts an “id” parameter and deletes the record with it. Once it execute the delete query, it will redirect the user to the index.php page.

3.0 Prepare The Database

3.1 Create the Database

On your PhpMyAdmin, create a database named “1phpbeginnercrudlevel1”.

If you’re not sure how to do it, please take a look at the following example. Follow only the “create database” part.

3.2 Create the Database Table

Next, run the following SQL code. This is to create our “products” database table. If you’re not sure how to do this, take a look at this resource.

--
-- Table structure for table `products`
--

CREATE TABLE IF NOT EXISTS `products` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(128) NOT NULL,
  `description` text NOT NULL,
  `price` double NOT NULL,
  `created` datetime NOT NULL,
  `modified` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB  DEFAULT CHARSET=latin1 AUTO_INCREMENT=9 ;

3.3 Dump Sample Data On The Table

Again, run the following SQL code on your PhpMyAdmin. This will insert the sample data or record on our ‘products’ database table.

--
-- Dumping data for table `products`
--

INSERT INTO `products` (`id`, `name`, `description`, `price`, `created`, `modified`) VALUES
(1, 'Basketball', 'A ball used in the NBA.', 49.99, '2015-08-02 12:04:03', '2015-08-06 06:59:18'),
(3, 'Gatorade', 'This is a very good drink for athletes.', 1.99, '2015-08-02 12:14:29', '2015-08-06 06:59:18'),
(4, 'Eye Glasses', 'It will make you read better.', 6, '2015-08-02 12:15:04', '2015-08-06 06:59:18'),
(5, 'Trash Can', 'It will help you maintain cleanliness.', 3.95, '2015-08-02 12:16:08', '2015-08-06 06:59:18'),
(6, 'Mouse', 'Very useful if you love your computer.', 11.35, '2015-08-02 12:17:58', '2015-08-06 06:59:18'),
(7, 'Earphone', 'You need this one if you love music.', 7, '2015-08-02 12:18:21', '2015-08-06 06:59:18'),
(8, 'Pillow', 'Sleeping well is important.', 8.99, '2015-08-02 12:18:56', '2015-08-06 06:59:18');


As you may have noticed, steps 1 and 2 are both SQL queries. Yes, they can run at the same time. But I wanted it to be on separate steps to emphasize those SQL queries’ purpose.

3.4 Create Database Connection PHP File

Create database.php file and put the following code inside it. It answers the question: how to connect to MySQL database with PDO?

<?php
// used to connect to the database
$host = "localhost";
$db_name = "1phpbeginnercrudlevel1";
$username = "root";
$password = "";

try {
	$con = new PDO("mysql:host={$host};dbname={$db_name}", $username, $password);
}

// show error
catch(PDOException $exception){
	echo "Connection error: " . $exception->getMessage();
}
?>

4.0 Create or Insert Record in PHP

4.1 HTML5 Boilerplate For create.php

Create a new “create.php” file. We will use it to create a new record to the database. Place the code following code inside the create.php file.

We use Bootstrap user interface for this project. Make sure you downloaded a copy and put it inside the “libs” folder.

If you are not familiar with Bootstrap, please learn our Bootstrap Tutorial for Beginners real quick.

<!DOCTYPE HTML>
<html>
<head>
	<title>PDO - Create a Record - PHP CRUD Tutorial</title>
	
	<!-- Bootstrap -->
	<!-- Latest compiled and minified CSS -->
	<link rel="stylesheet" href="libs/bootstrap-3.3.6/css/bootstrap.min.css" />
 
	<!-- HTML5 Shiv and Respond.js IE8 support of HTML5 elements and media queries -->
	<!-- WARNING: Respond.js doesn't work if you view the page via file:// -->
	<!--[if lt IE 9]>
	<script src="https://oss.maxcdn.com/libs/html5shiv/3.7.0/html5shiv.js"></script>
	<script src="https://oss.maxcdn.com/libs/respond.js/1.4.2/respond.min.js"></script>
	<![endif]-->
		
</head>
<body>

    <!-- container -->
    <div class="container">
 
        <div class="page-header">
            <h1>Create Product</h1>
        </div>
	
	<!-- dynamic content will be here -->
		
    </div> <!-- end .container -->
	
<!-- jQuery (necessary for Bootstrap's JavaScript plugins) -->
<script src="libs/jquery-3.0.0.min.js"></script>
 
<!-- Include all compiled plugins (below), or include individual files as needed -->
<script src="libs/bootstrap-3.3.6/js/bootstrap.min.js"></script>

</body>
</html>

4.2 HTML Form To Input New Record Data

Now we are going to start answering the question: how to create a record with PDO?

The code below will create an HTML form with input fields that matches the fields in the database. Place the following code between the “container div” tags of the previous section.

<!-- html form here where the product information will be entered -->
<form action="<?php echo htmlspecialchars($_SERVER["PHP_SELF"]);?>" method="post">
	<table class='table table-hover table-responsive table-bordered'>
		<tr>
			<td>Name</td>
			<td><input type='text' name='name' class='form-control' /></td>
		</tr>
		<tr>
			<td>Description</td>
			<td><textarea name='description' class='form-control'></textarea></td>
		</tr>
		<tr>
			<td>Price</td>
			<td><input type='text' name='price' class='form-control' /></td>
		</tr>
		<tr>
			<td></td>
			<td>
				<input type='submit' value='Save' class='btn btn-primary' />
				<a href='index.php' class='btn btn-danger'>Back to read products</a>
			</td>
		</tr>
	</table>
</form>

4.3 Code To Create A New Record

We are still working in the create.php file. Once the user filled out the form and clicked the save button, the code below will save it to the MySQL database. Put it above the opening “form” tag of the previous section.

<?php
if($_POST){

	// include database connection
	include 'config/database.php';

	try{
	
		// insert query
		$query = "INSERT INTO products SET name=:name, description=:description, price=:price, created=:created";

		// prepare query for execution
		$stmt = $con->prepare($query);

		// posted values
		$name=htmlspecialchars(strip_tags($_POST['name']));
		$description=htmlspecialchars(strip_tags($_POST['description']));
		$price=htmlspecialchars(strip_tags($_POST['price']));

		// bind the parameters
		$stmt->bindParam(':name', $name);
		$stmt->bindParam(':description', $description);
		$stmt->bindParam(':price', $price);
		
		// specify when this record was inserted to the database
		$created=date('Y-m-d H:i:s');
		$stmt->bindParam(':created', $created);
		
		// Execute the query
		if($stmt->execute()){
			echo "<div class='alert alert-success'>Record was saved.</div>";
		}else{
			echo "<div class='alert alert-danger'>Unable to save record.</div>";
		}
		
	}
	
	// show error
	catch(PDOException $exception){
		die('ERROR: ' . $exception->getMessage());
	}
}
?>

5.0 Read Records in PHP

5.1 Basic HTML Code For index.php

Create new index.php file. We prepare this to read records from the database. It answers the question: how to read records with PDO?

Place the following code inside the index.php file.

<!DOCTYPE HTML>
<html>
<head>
	<title>PDO - Read Records - PHP CRUD Tutorial</title>
	
	<!-- Bootstrap -->
	<!-- Latest compiled and minified CSS -->
	<link rel="stylesheet" href="libs/bootstrap-3.3.6/css/bootstrap.min.css" />
 
	<!-- HTML5 Shiv and Respond.js IE8 support of HTML5 elements and media queries -->
	<!-- WARNING: Respond.js doesn't work if you view the page via file:// -->
	<!--[if lt IE 9]>
	<script src="https://oss.maxcdn.com/libs/html5shiv/3.7.0/html5shiv.js"></script>
	<script src="https://oss.maxcdn.com/libs/respond.js/1.4.2/respond.min.js"></script>
	<![endif]-->
		
	<!-- custom css -->
	<style>
	.m-r-1em{ margin-right:1em; }
	.m-b-1em{ margin-bottom:1em; }
	.m-l-1em{ margin-left:1em; }
	</style>

</head>
<body>

    <!-- container -->
    <div class="container">
 
        <div class="page-header">
            <h1>Read Products</h1>
        </div>
	
	<!-- dynamic content will be here -->
		
    </div> <!-- end .container -->
	
<!-- jQuery (necessary for Bootstrap's JavaScript plugins) -->
<script src="libs/jquery-3.0.0.min.js"></script>
 
<!-- Include all compiled plugins (below), or include individual files as needed -->
<script src="libs/bootstrap-3.3.6/js/bootstrap.min.js"></script>

</body>
</html>

5.2 Read Records From The Database

This time we will read records from the database. Place the following code between the “container div” tags of the previous section.

<?php
// include database connection
include 'config/database.php';

// select all data
$query = "SELECT id, name, description, price FROM products ORDER BY id DESC";
$stmt = $con->prepare($query);
$stmt->execute();

// this is how to get number of rows returned
$num = $stmt->rowCount();

// link to create record form
echo "<a href='create.php' class='btn btn-primary m-b-1em'>Create New Product</a>";

//check if more than 0 record found
if($num>0){

	echo "<table class='table table-hover table-responsive table-bordered'>";//start table
	
		//creating our table heading
		echo "<tr>";
			echo "<th>ID</th>";
			echo "<th>Name</th>";
			echo "<th>Description</th>";
			echo "<th>Price</th>";
			echo "<th>Action</th>";
		echo "</tr>";
		
		// retrieve our table contents
		// fetch() is faster than fetchAll()
		// http://stackoverflow.com/questions/2770630/pdofetchall-vs-pdofetch-in-a-loop
		while ($row = $stmt->fetch(PDO::FETCH_ASSOC)){
			// extract row
			// this will make $row['firstname'] to
			// just $firstname only
			extract($row);
			
			// creating new table row per record
			echo "<tr>";
				echo "<td>{$id}</td>";
				echo "<td>{$name}</td>";
				echo "<td>{$description}</td>";
				echo "<td>&#36;{$price}</td>";
				echo "<td>";
					// read one record 
					echo "<a href='read_one.php?id={$id}' class='btn btn-info m-r-1em'>Read</a>";
					
					// we will use this links on next part of this post
					echo "<a href='update.php?id={$id}' class='btn btn-primary m-r-1em'>Edit</a>";

					// we will use this links on next part of this post
					echo "<a href='#' onclick='delete_user({$id});'  class='btn btn-danger'>Delete</a>";
				echo "</td>";
			echo "</tr>";
		}
	
	// end table
	echo "</table>";
	
}

// if no records found
else{
	echo "<div class='alert alert-danger'>No records found.</div>";
}
?>

The code above shows:

  • The inclusion of database.php file from section 3.4
  • The SELECT SQL query.
  • The HTML table where the retrieved data will be put.

6.0 Read One Record in PHP

6.1 Basic HTML Code For read_one.php

Create new read_one.php file. This is where we will read and display the details of a single database record. Place the following code inside read_one.php file.

<!DOCTYPE HTML>
<html>
<head>
	<title>PDO - Read One Record - PHP CRUD Tutorial</title>

	<!-- Bootstrap -->
	<!-- Latest compiled and minified CSS -->
	<link rel="stylesheet" href="libs/bootstrap-3.3.6/css/bootstrap.min.css" />
 
	<!-- HTML5 Shiv and Respond.js IE8 support of HTML5 elements and media queries -->
	<!-- WARNING: Respond.js doesn't work if you view the page via file:// -->
	<!--[if lt IE 9]>
	<script src="https://oss.maxcdn.com/libs/html5shiv/3.7.0/html5shiv.js"></script>
	<script src="https://oss.maxcdn.com/libs/respond.js/1.4.2/respond.min.js"></script>
	<![endif]-->

</head>
<body>


    <!-- container -->
    <div class="container">
 
        <div class="page-header">
            <h1>Read Product</h1>
        </div>
		
		<!-- dynamic content will be here -->

	</div> <!-- end .container -->
	
<!-- jQuery (necessary for Bootstrap's JavaScript plugins) -->
<script src="libs/jquery-3.0.0.min.js"></script>
 
<!-- Include all compiled plugins (below), or include individual files as needed -->
<script src="libs/bootstrap-3.3.6/js/bootstrap.min.js"></script>

</body>
</html>

6.2 Read One Record From The Database

The following code is how we retrieve a single database record. Place it between the “container div” tags of the previous section, under the closing “page-header div” tag.

<?php
// get passed parameter value, in this case, the record ID
// isset() is a PHP function used to verify if a value is there or not
$id=isset($_GET['id']) ? $_GET['id'] : die('ERROR: Record ID not found.');

//include database connection
include 'config/database.php';

// read current record's data
try {
	// prepare select query
	$query = "SELECT id, name, description, price FROM products WHERE id = ? LIMIT 0,1";
	$stmt = $con->prepare( $query );

	// this is the first question mark
	$stmt->bindParam(1, $id);

	// execute our query
	$stmt->execute();

	// store retrieved row to a variable
	$row = $stmt->fetch(PDO::FETCH_ASSOC);

	// values to fill up our form
	$name = $row['name'];
	$description = $row['description'];
	$price = $row['price'];
}

// show error
catch(PDOException $exception){
	die('ERROR: ' . $exception->getMessage());
}
?>

6.3 Display Record Details

The following HTML table will hold and display the details of a single database record. Put the following code after the previous section’s code.

<!--we have our html table here where new user information will be displayed-->
<table class='table table-hover table-responsive table-bordered'>
	<tr>
		<td>Name</td>
		<td><?php echo htmlspecialchars($name, ENT_QUOTES);  ?></td>
	</tr>
	<tr>
		<td>Description</td>
		<td><?php echo htmlspecialchars($description, ENT_QUOTES);  ?></td>
	</tr>
	<tr>
		<td>Price</td>
		<td><?php echo htmlspecialchars($price, ENT_QUOTES);  ?></td>
	</tr>
	<tr>
		<td></td>
		<td>
			<a href='index.php' class='btn btn-danger'>Back to read products</a>
		</td>
	</tr>
</table>

7.0 Update Record in PHP

7.1 Basic HTML Code For udpate.php

Create new “update.php” file. We are preparing to update a selected record from the database. This will answer the question: how to update a record with PDO?

Place the following code inside the new update.php file.

<!DOCTYPE HTML>
<html>
<head>
	<title>PDO - Update a Record - PHP CRUD Tutorial</title>
	
	<!-- Bootstrap -->
	<!-- Latest compiled and minified CSS -->
	<link rel="stylesheet" href="libs/bootstrap-3.3.6/css/bootstrap.min.css" />
 
	<!-- HTML5 Shiv and Respond.js IE8 support of HTML5 elements and media queries -->
	<!-- WARNING: Respond.js doesn't work if you view the page via file:// -->
	<!--[if lt IE 9]>
	<script src="https://oss.maxcdn.com/libs/html5shiv/3.7.0/html5shiv.js"></script>
	<script src="https://oss.maxcdn.com/libs/respond.js/1.4.2/respond.min.js"></script>
	<![endif]-->
		
</head>
<body>

    <!-- container -->
    <div class="container">
 
        <div class="page-header">
            <h1>Update Product</h1>
        </div>
	
	<!-- dynamic content will be here -->
		
    </div> <!-- end .container -->
	
<!-- jQuery (necessary for Bootstrap's JavaScript plugins) -->
<script src="libs/jquery-3.0.0.min.js"></script>
 
<!-- Include all compiled plugins (below), or include individual files as needed -->
<script src="libs/bootstrap-3.3.6/js/bootstrap.min.js"></script>

</body>
</html>

7.2 Read A Record By ID Parameter

We have to get the record ID and store it in the $id variable. We access the $_GET[‘id’] variable to do it.

What we are trying to do here is to get the related data based on the given record ID. This is the way to auto-fill the HTML form with existing data from the database.

Place the following code between the “container div” tags of the previous section, under the closing “page-header div” tag.

<?php
// get passed parameter value, in this case, the record ID
// isset() is a PHP function used to verify if a value is there or not
$id=isset($_GET['id']) ? $_GET['id'] : die('ERROR: Record ID not found.');

//include database connection
include 'config/database.php';

// read current record's data
try {
	// prepare select query
	$query = "SELECT id, name, description, price FROM products WHERE id = ? LIMIT 0,1";
	$stmt = $con->prepare( $query );
	
	// this is the first question mark
	$stmt->bindParam(1, $id);
	
	// execute our query
	$stmt->execute();
	
	// store retrieved row to a variable
	$row = $stmt->fetch(PDO::FETCH_ASSOC);
	
	// values to fill up our form
	$name = $row['name'];
	$description = $row['description'];
	$price = $row['price'];
}

// show error
catch(PDOException $exception){
	die('ERROR: ' . $exception->getMessage());
}
?>

7.3 HTML Form To Update A Record

This form shows data retrieved using the previous section’s code. We read a single record from the database, based on given ID parameter.

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

<!--we have our html form here where new user information will be entered-->
<form action="<?php echo htmlspecialchars($_SERVER["PHP_SELF"] . "?id={$id}");?>" method="post">
	<table class='table table-hover table-responsive table-bordered'>
		<tr>
			<td>Name</td>
			<td><input type='text' name='name' value="<?php echo htmlspecialchars($name, ENT_QUOTES);  ?>" class='form-control' /></td>
		</tr>
		<tr>
			<td>Description</td>
			<td><textarea name='description' class='form-control'><?php echo htmlspecialchars($description, ENT_QUOTES);  ?></textarea></td>
		</tr>
		<tr>
			<td>Price</td>
			<td><input type='text' name='price' value="<?php echo htmlspecialchars($price, ENT_QUOTES);  ?>" class='form-control' /></td>
		</tr>
		<tr>
			<td></td>
			<td>
				<input type='submit' value='Save Changes' class='btn btn-primary' />
				<a href='index.php' class='btn btn-danger'>Back to read products</a>
			</td>
		</tr>
	</table>
</form>

7.4 Code To Update The Record

The following code will save the changes in the database.

That is if the user change some value on the form and hit the “Save Changes” button. Place the following code before the previous section’s code.

<?php
// get passed parameter value, in this case, the record ID
// isset() is a PHP function used to verify if a value is there or not
$id=isset($_GET['id']) ? $_GET['id'] : die('ERROR: Record ID not found.');

//include database connection
include 'config/database.php';

// check if form was submitted
if($_POST){
	
	try{
	
		// write update query
		// in this case, it seemed like we have so many fields to pass and 
		// it is better to label them and not use question marks
		$query = "UPDATE products 
					SET name=:name, description=:description, price=:price 
					WHERE id = :id";

		// prepare query for excecution
		$stmt = $con->prepare($query);

		// posted values
		$name=htmlspecialchars(strip_tags($_POST['name']));
		$description=htmlspecialchars(strip_tags($_POST['description']));
		$price=htmlspecialchars(strip_tags($_POST['price']));

		// bind the parameters
		$stmt->bindParam(':name', $name);
		$stmt->bindParam(':description', $description);
		$stmt->bindParam(':price', $price);
		$stmt->bindParam(':id', $id);
		
		// Execute the query
		if($stmt->execute()){
			echo "<div class='alert alert-success'>Record was updated.</div>";
		}else{
			echo "<div class='alert alert-danger'>Unable to update record. Please try again.</div>";
		}
		
	}
	
	// show errors
	catch(PDOException $exception){
		die('ERROR: ' . $exception->getMessage());
	}
}
?>

8.0 Delete Record in PHP

8.1 Tell The User If Record Was Deleted

Place the following code right after the include ‘config/database.php’; line of index.php file.

This will tell the user if there is a deleted record after clicking the delete button and “ok” in the pop up.

$action = isset($_GET['action']) ? $_GET['action'] : "";

// if it was redirected from delete.php
if($action=='deleted'){
	echo "<div class='alert alert-success'>Record was deleted.</div>";
}

8.2 JavaScript To Verify Record Deletion

The user clicks on the “Delete” button in index.php. Next, he will verify the deletion by clicking “OK” on the pop up.

That user activity will execute the following JavaScript code. Put it before the closing “body” tag in index.php file.

<script type='text/javascript'>
function delete_user( id ){
	
	var answer = confirm('Are you sure?');
	if (answer){
		// if user clicked ok, 
		// pass the id to delete.php and execute the delete query
		window.location = 'delete.php?id=' + id;
	} 
}
</script>

8.3 Delete Record From The Database

The code below will delete a record from the database using the given ID parameter.

This answers the question: how to delete a record with PDO? Create new delete.php file, place the following code and save it.

<?php
// include database connection
include 'config/database.php';

try {
	
	// get record ID
	// isset() is a PHP function used to verify if a value is there or not
	$id=isset($_GET['id']) ? $_GET['id'] : die('ERROR: Record ID not found.');

	// delete query
	$query = "DELETE FROM products WHERE id = ?";
	$stmt = $con->prepare($query);
	$stmt->bindParam(1, $id);
	
	if($stmt->execute()){
		// redirect to read records page and 
		// tell the user record was deleted
		header('Location: index.php?action=deleted');
	}else{
		die('Unable to delete record.');
	}
}

// show error
catch(PDOException $exception){
	die('ERROR: ' . $exception->getMessage());
}
?>

9.0 Pagination in PHP

Please note that this is a bonus section and is not included in the LEVEL 1 source code download. We will have to add or remove some codes we’ve done above so that pagination will work.

9.1 Set Pagination Variables

Place the following code below include ‘config/database.php’; line of index.php file.

// PAGINATION VARIABLES
// page is the current page, if there's nothing set, default is page 1
$page = isset($_GET['page']) ? $_GET['page'] : 1;

// set records or rows of data per page
$records_per_page = 5;

// calculate for the query LIMIT clause
$from_record_num = ($records_per_page * $page) - $records_per_page;

9.2 Add LIMIT Clause in SELECT Query

This will enable paginated requests to database. Still on index.php file, change the following code from:

$query = "SELECT id, name, description, price FROM products ORDER BY id DESC";
$stmt = $con->prepare($query);
$stmt->execute();

to:

// select data for current page
$query = "SELECT id, name, description, price FROM products ORDER BY id DESC
	LIMIT :from_record_num, :records_per_page";

$stmt = $con->prepare($query);
$stmt->bindParam(":from_record_num", $from_record_num, PDO::PARAM_INT);
$stmt->bindParam(":records_per_page", $records_per_page, PDO::PARAM_INT);
$stmt->execute();

9.3 Count Total Number Of Records

Counting the total number of records will help calculate the correct pagination numbers. Below the closing ‘table’ tag in index.php file, add the following code.

// PAGINATION
// count total number of rows
$query = "SELECT COUNT(*) as total_rows FROM products";
$stmt = $con->prepare($query);

// execute query
$stmt->execute();

// get total rows
$row = $stmt->fetch(PDO::FETCH_ASSOC);
$total_rows = $row['total_rows'];

9.4 Include Paging File

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

// paginate records
$page_url="index.php?";
include_once "paging.php";

Why a $page_url variable is needed? Because we made paging.php re-usable. You can use it for other objects you want to paginate.

For example you’re trying to paginate your read_categories.php, you do $page_url=”read_categories.php?”;

You will have to follow the code pattern of section 9.1 to 9.3 when you use paging.php file.

9.5 Create paging.php

Create new paging.php file. Place the following code and save it.

<?php
// *************** <PAGING_SECTION> ***************
echo "<nav class='overflow-hidden'>";
	echo "<ul class='pagination pull-left margin-zero'>";

	// ***** for 'first' and 'previous' pages
	if($page>1){

		// ********** show the previous page
		$prev_page = $page - 1;
		echo "<li>";
			echo "<a href='{$page_url}page={$prev_page}'>";
				echo "<span style='margin:0 .5em;'>&laquo;</span>";
			echo "</a>";
		echo "</li>";
	}


	// ********** show the number paging

	// find out total pages
	$total_pages = ceil($total_rows / $records_per_page);

	// range of num links to show
	$range = 1;

	// display links to 'range of pages' around 'current page'
	$initial_num = $page - $range;
	$condition_limit_num = ($page + $range)  + 1;

	for ($x=$initial_num; $x<$condition_limit_num; $x++) {

		// be sure '$x is greater than 0' AND 'less than or equal to the $total_pages'
		if (($x > 0) && ($x <= $total_pages)) {

			// current page
			if ($x == $page) {
				echo "<li class='active'>";
					echo "<a href='javascript::void();'>{$x}</a>";
				echo "</li>";
			}

			// not current page
			else {
				echo "<li>";
					echo " <a href='{$page_url}page={$x}'>{$x}</a> ";
				echo "</li>";
			}
		}
	}


	// ***** for 'next' and 'last' pages
	if($page<$total_pages){
		// ********** show the next page
		$next_page = $page + 1;

		echo "<li>";
			echo "<a href='{$page_url}page={$next_page}'>";
				echo "<span style='margin:0 .5em;'>&raquo;</span>";
			echo "</a>";
		echo "</li>";
	}

	echo "</ul>";

echo "</nav>";
// *************** </PAGING_SECTION> ***************
?>

10.0 File Upload in PHP

Now we are going to add a “file upload” feature when creating a record.

10.1 Add HTML “file” field

Open create.php file and scroll down to the form. Find the opening “form” tag and enable the file upload by changing it to:

<form action="<?php echo htmlspecialchars($_SERVER["PHP_SELF"]);?>" method="post" enctype="multipart/form-data">

Find the closing “tr” tag of the “price” field. Once found, add the following code after it.

<tr>
	<td>Photo</td>
	<td><input type="file" name="image" /></td>
</tr>

10.2 Add “image” field

Still in create.php file. Scroll up and change the “insert” SQL query. It should look like the following code. The new “image” field will store the file name of the submitted file.

// insert query
$query = "INSERT INTO products
			SET name=:name, description=:description,
				price=:price, image=:image, created=:created";

// prepare query for execution
$stmt = $con->prepare($query);

$name=htmlspecialchars(strip_tags($_POST['name']));
$description=htmlspecialchars(strip_tags($_POST['description']));
$price=htmlspecialchars(strip_tags($_POST['price']));

// new 'image' field
$image=!empty($_FILES["image"]["name"])
		? sha1_file($_FILES['image']['tmp_name']) . "-" . basename($_FILES["image"]["name"])
		: "";
$image=htmlspecialchars(strip_tags($image));

// bind the parameters
$stmt->bindParam(':name', $name);
$stmt->bindParam(':description', $description);
$stmt->bindParam(':price', $price);
$stmt->bindParam(':image', $image);

// specify when this record was inserted to the database
$created=date('Y-m-d H:i:s');
$stmt->bindParam(':created', $created);

Using PhpMyAdmin, add an “image” field in the products table as well.

10.3 Set variables for file upload

We will start the code for the “file upload” feature. Find the following line in create.php file.

echo "<div class='alert alert-success'>Record was saved to database.</div>";

Under the code above, we will add the following code. The “if($image){” code will verify if there’s an uploaded image. If there is, inside the “if” statement, we will set the initial variables needed for the file upload.

// now, if image is not empty, try to upload the image
if($image){

	// sha1_file() function is used to make a unique file name
	$target_directory = "uploads/";
	$target_file = $target_directory . $image;
	$file_type = pathinfo($target_file, PATHINFO_EXTENSION);

	// error message is empty
	$file_upload_error_messages="";

}

10.4 Make sure submitted file is a real image

Now we will start validating the submitted file. The code below will identify if the submitted file is a real or fake image.

Place the following code under $file_upload_error_messages=””; of the previous section.

// make sure that file is a real image
$check = getimagesize($_FILES["image"]["tmp_name"]);
if($check!==false){
	// submitted file is an image
}else{
	$file_upload_error_messages.="<div>Submitted file is not an image.</div>";
}

10.5 Make sure certain file types are allowed

The following code will limit the allowed file types. Place it under the code of the previous section.

// make sure certain file types are allowed
$allowed_file_types=array("jpg", "jpeg", "png", "gif");
if(!in_array($file_type, $allowed_file_types)){
	$file_upload_error_messages.="<div>Only JPG, JPEG, PNG, GIF files are allowed.</div>";
}

10.6 Make sure file does not exist

There’s a very small chance that the submitted file name will be the same with the one that exists in the server. This is because of the sha1_file() method we used on section 10.2 above.

But just in case there’s a file with the same name, tell the user. Place the following code after the previous section’s code.

// make sure file does not exist
if(file_exists($target_file)){
	$file_upload_error_messages.="<div>Image already exists. Try to change file name.</div>";
}

10.7 Make sure submitted file is not too large

Uploading a very large photo is not recommended in this case. So we will set the file size limit to less than 1 MB. Place the following code after the code of the previous section.

// make sure submitted file is not too large, can't be larger than 1 MB
if($_FILES['image']['size'] > (1024000)){
	$file_upload_error_messages.="<div>Image must be less than 1 MB in size.</div>";
}

10.8 Make sure the ‘uploads’ folder exists

The “uploads” folder is where we will put the submitted file. Make sure it exists by using the following code. Place it under the code of the previous section.

// make sure the 'uploads' folder exists
// if not, create it
if(!is_dir($target_directory)){
	mkdir($target_directory, 0777, true);
}

10.9 Try to upload the file

The “move_uploaded_file” built in PHP function will place the uploaded file on the server directory. Place the following code under the previous section’s code.

// if $file_upload_error_messages is still empty
if(empty($file_upload_error_messages)){
	// it means there are no errors, so try to upload the file
	if(move_uploaded_file($_FILES["image"]["tmp_name"], $target_file)){
		// it means photo was uploaded
	}else{
		echo "<div class='alert alert-danger'>";
			echo "<div>Unable to upload photo.</div>";
			echo "<div>Update the record to upload photo.</div>";
		echo "</div>";
	}
}

// if $file_upload_error_messages is NOT empty
else{
	// it means there are some errors, so show them to user
	echo "<div class='alert alert-danger'>";
		echo "<div>{$file_upload_error_messages}</div>";
		echo "<div>Update the record to upload photo.</div>";
	echo "</div>";
}

10.10 Show image in “read one” page

Open read_one.php file and apply the following changes to the code.

Add ‘image’ field to the $query variable. It should look like the following.

$query = "SELECT id, name, description, price, image FROM products WHERE id = ? LIMIT 0,1";

Add ‘$image’ variable after the ‘$price’ variable.

$image = htmlspecialchars($row['image'], ENT_QUOTES);

Find the closing ‘tr’ tag of the ‘Price’ field in the HTML table and put the following code after it. It will show the uploaded image or ‘No image found.’ if no image was uploaded.

<tr>
	<td>Image</td>
	<td>
	<?php echo $image ? "<img src='uploads/{$image}' style='width:300px;' />" : "No image found.";  ?>
	</td>
</tr>

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. Create your database using PhpMyAdmin, database name is “php_beginner_crud_3” – if you downloaded our LEVEL 3 source code.
  3. Import the SQL file called “php_beginner_crud_3.sql” located in the “dev” folder.
  4. You run index.php on the browser.

12.0 Download LEVEL 1 Source Code

FEATURES LEVEL 1
PDO extension used YES
Create product YES
Read product YES
Update product YES
Delete 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
HTML5 (font-end) validation for create product YES
HTML5 (font-end) validation for update product YES
Category selection for create and update product. YES
Bootstrap UI YES
Buttons with Glyphicons YES
Pagination YES
Search products by name or description YES
HTML5 (font-end) validation for search product YES
Pagination in search YES
Allow user to input page number (read and search list) YES
Export / download records to CSV YES
Price display with dollar sign, comma and decimal point YES
Multiple delete YES
Create & update record with file upload YES
Download Now

14.0 Download LEVEL 3 Source Code

FEATURES LEVEL 3
All features of LEVEL 1 and 2 above YES
Bootstrap navigation bar YES
Select category in navigation YES
Higlight category in navigation YES
Create category YES
Read category YES
Update category YES
Delete category YES
View products by category YES
Pagination for category YES
Search category YES
Pagination for category search YES
Server side validation for create product & category YES
Server side validation for update product & category YES
Sorting by fields YES
Pagination for sorting by fields YES
jQuery UI enabled YES
Search product by date range – record date created YES
Pagination for earch product by date range YES
jQuery UI calendar for picking date YES
Download Now

15.0 Download ALL LEVELS

This means you will download the LEVEL 1, 2 and 3 source codes in separate packages. Select “ALL LEVELS Source Code” 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 Bootstrap and PHP 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

If you have any more questions, please feel free to contact me now. You can do it by sending a message on our official Facebook page, or via my email mike@codeofaninja.com

Thanks for supporting our website and projects here at codeofaninja.com!

16.0 Online Resources

17.0 What’s Next?

After learning from this PHP CRUD tutorial, we can go one step higher. We can do this by learning object-oriented programming (OOP) in PHP.

Object-oriented programming (OOP) is a programming language model organized around objects rather than “actions” and data rather than logic. This is very exciting.

To learn more, we created the next tutorial just for you! Let’s go and learn:
PHP, MySQL and OOP CRUD Tutorial – Step by Step Guide!

18.0 Related Tutorials

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

Please share this post if you think this is a useful PHP CRUD Tutorial. We hope you mastered how to create, read, update and delete database records and more. Thanks for learning here in codeofaninja.com!