article

Saturday, January 8, 2022

AngularJS PHP Mysqli CRUD (Create, Read, Update and Delete) with Pagination, Search and Sort

AngularJS PHP Mysqli CRUD (Create, Read, Update and Delete) with Pagination, Search and Sort

Bootstrap 5.1 Version
https://getbootstrap.com/docs/5.1/getting-started/introduction/

https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css

angularjs CDN 
https://angularjs.org/ Version 1.8.2 https://ajax.googleapis.com/ajax/libs/angularjs/1.8.2/angular.min.js

dirPagination - AngularJS module for paginating

https://github.com/michaelbromley/angularUtils/tree/master/src/directives/pagination

https://github.com/michaelbromley/angularUtils/blob/master/src/directives/pagination/dirPagination.js

CREATE TABLE `employee` (
  `id` int(11) NOT NULL,
  `name` varchar(100) NOT NULL,
  `position` varchar(100) NOT NULL,
  `office` varchar(100) NOT NULL,
  `age` int(11) NOT NULL,
  `salary` int(11) NOT NULL,
  `created_at` date NOT NULL DEFAULT current_timestamp()
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

INSERT INTO `employee` (`id`, `name`, `position`, `office`, `age`, `salary`, `created_at`) VALUES
(1, 'Tiger Wood', 'Accountant', 'Tokyo', 36, 5689, '2020-01-09'),
(2, 'Mark Oto Ednalan', 'Chief Executive Officer (CEO)', 'London', 56, 5648, '2020-02-15'),
(3, 'Jacob thompson', 'Junior Technical Author', 'San Francisco', 23, 5689, '2020-03-01'),
(4, 'cylde Ednalan', 'Software Engineer', 'Olongapo', 23, 54654, '2020-01-24'),
(5, 'Rhona Davidson', 'Software Engineer', 'San Francisco', 26, 5465, '2020-01-11'),
(6, 'Quinn Flynn', 'Integration Specialist', 'New York', 53, 56465, '2020-02-23'),
(8, 'Tiger Nixon', 'Software Engineer', 'London', 45, 456, '2020-03-04'),
(9, 'Airi Satou updated', 'Pre-Sales Support updated', 'New York', 25, 4568, '2020-04-28'),
(10, 'Angelica Ramos updated', 'Sales Assistant updated', 'New York', 45, 456, '2020-01-12'),
(11, 'Ashton updated', 'Senior Javascript Developer', 'Olongapo', 45, 54565, '2020-02-06'),
(12, 'Bradley Greer', 'Regional Director', 'San Francisco', 27, 5485, '2020-03-21'),
(13, 'Brenden Wagner', 'Javascript Developer', 'San Francisco', 38, 65468, '2020-04-14'),
(14, 'Brielle Williamson', 'Personnel Lead', 'Olongapo', 56, 354685, '2020-01-29'),
(15, 'Bruno Nash', 'Customer Support', 'New York', 36, 65465, '2020-02-22'),
(16, 'cairocoders', 'Sales Assistant', 'Sydney', 45, 56465, '2020-03-10'),
(17, 'Zorita Serrano', 'Support Engineer', 'San Francisco', 38, 6548, '2020-04-26'),
(18, 'Zenaida Frank', 'Chief Operating Officer (COO)', 'San Francisco', 39, 545, '2020-01-17'),
(19, 'Sakura Yamamoto', 'Support Engineer', 'Tokyo', 48, 5468, '2020-02-01'),
(20, 'Serge Baldwin', 'Data Coordinator', 'Singapore', 85, 5646, '2020-03-19'),
(21, 'Shad Decker', 'Regional Director', 'Tokyo', 45, 4545, '2020-04-21');

ALTER TABLE `employee`
  ADD PRIMARY KEY (`id`);

ALTER TABLE `employee`
  MODIFY `id` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=22;

index.php
//index.php
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>AngularJS PHP Mysqli CRUD with Pagination Search and Sort </title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous">
<link href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet">
    
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.8.2/angular.min.js"></script>
<link rel="stylesheet" type="text/css" href="style.css">
</head>
<body ng-app="employeeapp" ng-controller="employeeCTR" ng-init="fetch()">
<div class="container">
    <h1 class="page-header text-center">AngularJS PHP Mysqli CRUD (Create, Read, Update and Delete) with Pagination, Search and Sort</h1>
    <div class="row">
		<div class="col-md-12">
			<div class="alert alert-success text-center" ng-show="success">
				<button type="button" class="close" ng-click="clearMessage()"><span aria-hidden="true">×</span></button>
				<i class="fa fa-check"></i> {{ successMessage }}
			</div>
			<div class="alert alert-danger text-center" ng-show="error">
				<button type="button" class="close" ng-lick="clearMessage()"><span aria-hidden="true">×</span></button>
				<i class="fa fa-warning"></i> {{ errorMessage }}
			</div>
			<div class="row">
				<div class="col-md-12">
					<button href="" class="btn btn-primary" ng-click="showAdd()"><i class="fa fa-plus"></i> Add New New Employee</button>
					<span class="pull-right">
						<input type="text" ng-model="search" class="form-control" placeholder="Search">
					</span>
				</div>
			</div>
			<table class="table table-bordered table-striped" style="margin-top:10px;">
				<thead>
                    <tr>
                        <th ng-click="sort('name')" class="text-center">Name
                        	<span class="pull-right">
                       			<i class="fa fa-sort gray" ng-show="sortKey!='name'"></i>
                       			<i class="fa fa-sort" ng-show="sortKey=='name'" ng-class="{'fa fa-sort-asc':reverse,'fa fa-sort-desc':!reverse}"></i>
                       		</span>
                        </th>
                        <th ng-click="sort('position')" class="text-center">Position
	                        <span class="pull-right">
	                       		<i class="fa fa-sort gray" ng-show="sortKey!='position'"></i>
	                       		<i class="fa fa-sort" ng-show="sortKey=='position'" ng-class="{'fa fa-sort-asc':reverse,'fa fa-sort-desc':!reverse}"></i>
	                       	</span>
                        </th>
                        <th ng-click="sort('office')" class="text-center">Office
                        	<span class="pull-right">
                       			<i class="fa fa-sort gray" ng-show="sortKey!='office'"></i>
                       			<i class="fa fa-sort" ng-show="sortKey=='office'" ng-class="{'fa fa-sort-asc':reverse,'fa fa-sort-desc':!reverse}"></i>
                       		</span>
                       	</th>                        
						<th class="text-center">Age</th>
                       	<th class="text-center">Salary</th>
                       	<th class="text-center">Action</th>
                    </tr>
                </thead>
				<tbody>
					<tr dir-paginate="rs in employee|orderBy:sortKey:reverse|filter:search|itemsPerPage:5">
						<td>{{ rs.name }}</td>
						<td>{{ rs.position }}</td>
						<td>{{ rs.office }}</td>
						<td>{{ rs.age }}</td>
						<td>$ {{ rs.salary }}</td>
						<td>
							<button type="button" class="btn btn-success" ng-click="showEdit(); selectEmployee(rs);"><i class="fa fa-edit"></i> Edit</button> 
							<button type="button" class="btn btn-danger" ng-click="showDelete(); selectEmployee(rs);"> <i class="fa fa-trash"></i> Delete</button>
						</td>

					</tr>
				</tbody>
			</table>
			<div class="pull-right" style="margin-top:-30px;">
				<dir-pagination-controls
				   max-size="5"
				   direction-links="true"
				   boundary-links="true" >
				</dir-pagination-controls>
				

			</div>
  
  
		</div>
	</div>
	<?php include('modal.php'); ?>
</div>
<script src="dirPaginate.js"></script>
<script src="angular.js"></script>
<style>
.pagination {
    display: inline-block;
    padding-left: 0;
    margin: 20px 0;
    border-radius: 4px;
}
.pagination>li {
    display: inline;
}
.pagination>li:first-child>a, .pagination>li:first-child>span {
    margin-left: 0;
    border-top-left-radius: 4px;
    border-bottom-left-radius: 4px;
}
.pagination>.disabled>a, .pagination>.disabled>a:focus, .pagination>.disabled>a:hover, .pagination>.disabled>span, .pagination>.disabled>span:focus, .pagination>.disabled>span:hover {
    color: #777;
    cursor: not-allowed;
    background-color: #fff;
    border-color: #ddd;
}
.pagination>li>a, .pagination>li>span {
    position: relative;
    float: left;
    padding: 6px 12px;
    margin-left: -1px;
    line-height: 1.42857143;
    color: #337ab7;
    text-decoration: none;
    background-color: #fff;
    border: 1px solid #ddd;
}
.pagination>.active>a, .pagination>.active>a:focus, .pagination>.active>a:hover, .pagination>.active>span, .pagination>.active>span:focus, .pagination>.active>span:hover {
    z-index: 3;
    color: #fff;
    cursor: default;
    background-color: #337ab7;
    border-color: #337ab7;
}
</style>
</body>
</html>
angular.js
//angular.js
var app = angular.module('employeeapp', ['angularUtils.directives.dirPagination']);
app.controller('employeeCTR',function($scope, $http, $window){
	$scope.AddModal = false;
    $scope.EditModal = false;
    $scope.DeleteModal = false;

    $scope.errorname = false;

    $scope.showAdd = function(){
    	$scope.name = null;
    	$scope.position = null;
    	$scope.office = null;
    	$scope.errorname = false;
    	$scope.errorposition = false;
    	$scope.erroroffice = false;
    	$scope.AddModal = true;
    }
  
	$scope.fetch = function(){
        $http({
			method: 'GET',
            url: 'fetch.php',
        }).then(function (data){
            console.log(data)
            $scope.employee = data.data;      
        },function (error){
            console.log(error, 'can not get data.');
        });
    }

    $scope.sort = function(keyname){
        $scope.sortKey = keyname;   
        $scope.reverse = !$scope.reverse;
    }

    $scope.clearMessage = function(){
    	$scope.success = false;
    	$scope.error = false;
    }

    $scope.addnew = function(){
        $http({
			method: 'POST',
            url: 'add.php',
			data:{name:$scope.name, position:$scope.position, office:$scope.office}
        }).then(function (data){
            console.log(data)
        	if(data.data.name){
        		$scope.errorname = true;
        		$scope.errorposition = false;
        		$scope.erroroffice = false;
        		$scope.errorMessage = data.data.message;
        		$window.document.getElementById('name').focus();
        	}
        	else if(data.data.position){
        		$scope.errorname = false;
        		$scope.errorposition = true;
        		$scope.erroroffice = false;
        		$scope.errorMessage = data.data.message;
        		$window.document.getElementById('position').focus();
        	}
        	else if(data.data.office){
        		$scope.errorname = false;
        		$scope.errorposition = false;
        		$scope.erroroffice = true;
        		$scope.errorMessage = data.data.message;
        		$window.document.getElementById('office').focus();
        	}
        	else if(data.data.error){
        		$scope.errorname = false;
        		$scope.errorposition = false;
        		$scope.erroroffice = false;
        		$scope.error = true;
        		$scope.errorMessage = data.data.message;
        	}
        	else{
        		$scope.AddModal = false;
        		$scope.success = true;
        		$scope.successMessage = data.data.message;
        		$scope.fetch();
        	}     
        },function (error){
            console.log(error, 'can not get data.');
        });
    }

    $scope.selectEmployee = function(employee){
    	$scope.clickEmployee = employee;
    }

    $scope.showEdit = function(){
    	$scope.EditModal = true;
    }

    $scope.updateEmployee = function(){
        $http({
			method: 'POST',
            url: 'edit.php',
			data: $scope.clickEmployee
        }).then(function (data){
            console.log(data)
        	if(data.error){
        		$scope.error = true;
        		$scope.errorMessage = data.data.message;
        		$scope.fetch();
        	}
        	else{
        		$scope.success = true;
        		$scope.successMessage = data.data.message;
        	}     
        },function (error){
            console.log(error, 'can not get data.');
        });
    }

    $scope.showDelete = function(){
    	$scope.DeleteModal = true;
    }

    $scope.deleteEmployee = function(){
        $http({
			method: 'POST',
            url: 'delete.php',
			data: $scope.clickEmployee
        }).then(function (data){
            console.log(data)
        	if(data.data.error){
        		$scope.error = true;
        		$scope.errorMessage = data.data.message;
        	}
        	else{
        		$scope.success = true;
        		$scope.successMessage = data.data.message;
        		$scope.fetch();
        	}  
        },function (error){
            console.log(error, 'can not get data.');
        });
    }

});
conn.php
//conn.php
<?php
	$conn = new mysqli('localhost', 'root', '', 'testingdb');

	if ($conn->connect_error) {
	    die("Connection failed: " . $conn->connect_error);
	}
?>
fetch.php
//fetch.php
<?php
	include('conn.php');
	
	$output = array();
	$sql = "SELECT * FROM employee";
	$query=$conn->query($sql);
	while($row=$query->fetch_array()){
		$output[] = $row;
	}

	echo json_encode($output);
?>
modal.php
//modal.php
<!-- Add Modal -->
<div class="myModal" ng-show="AddModal">
	<div class="modalContainer">
		<div class="modalHeader">
			<span class="headerTitle">Add New Employee</span>
			<button class="closeBtn pull-right" ng-click="AddModal = false">×</button>
		</div>
		<div class="modalBody">
			<div class="form-group">
				<label>Name:</label>
				<input type="text" class="form-control" ng-model="name" id="name">
				<span class="pull-right input-error" ng-show="errorFirstname">{{ errorMessage }}</span>
			</div>
			<div class="form-group">
				<label>Position:</label>
				<input type="text" class="form-control" ng-model="position" id="position">
				<span class="pull-right input-error" ng-show="errorposition">{{ errorMessage }}</span>
			</div>
			<div class="form-group">
				<label>Office:</label>
				<input type="text" class="form-control" ng-model="office" id="office">
				<span class="pull-right input-error" ng-show="erroroffice">{{ errorMessage }}</span>
			</div>
		</div>
		<hr>
		<div class="modalFooter">
			<div class="footerBtn pull-right">
				<button class="btn btn-default" ng-click="AddModal = false"><span class="glyphicon glyphicon-remove"></span> Cancel</button> <button class="btn btn-primary" ng-click="addnew()"><span class="glyphicon glyphicon-floppy-disk"></span> Save</button>
			</div>
		</div>
	</div>
</div>

<!-- Edit Modal -->
<div class="myModal" ng-show="EditModal">
	<div class="modalContainer">
		<div class="editHeader">
			<span class="headerTitle">Edit Employee</span>
			<button class="closeEditBtn pull-right" ng-click="EditModal = false">×</button>
		</div>
		<div class="modalBody">
			<div class="form-group">
				<label>Name:</label>
				<input type="text" class="form-control" ng-model="clickEmployee.name">
			</div>
			<div class="form-group">
				<label>Position:</label>
				<input type="text" class="form-control" ng-model="clickEmployee.position">
			</div>
			<div class="form-group">
				<label>Office:</label>
				<input type="text" class="form-control" ng-model="clickEmployee.office">
			</div>
		</div>
		<hr>
		<div class="modalFooter">
			<div class="footerBtn pull-right">
				<button class="btn btn-default" ng-click="EditModal = false"><span class="glyphicon glyphicon-remove"></span> Cancel</button> <button class="btn btn-success" ng-click="EditModal = false; updateEmployee();"><span class="glyphicon glyphicon-check"></span> Save</button>
			</div>
		</div>
	</div>
</div>

<!-- Delete Modal -->
<div class="myModal" ng-show="DeleteModal">
	<div class="modalContainer">
		<div class="deleteHeader">
			<span class="headerTitle">Delete Employee</span>
			<button class="closeDelBtn pull-right" ng-click="DeleteModal = false">×</button>
		</div>
		<div class="modalBody">
			<h5 class="text-center">Are you sure you want to delete</h5>
			<h2 class="text-center">{{clickEmployee.name}}</h2>
		</div>
		<hr>
		<div class="modalFooter">
			<div class="footerBtn pull-right">
				<button class="btn btn-default" ng-click="DeleteModal = false"><span class="glyphicon glyphicon-remove"></span> Cancel</button> <button class="btn btn-danger" ng-click="DeleteModal = false; deleteEmployee(); "><span class="glyphicon glyphicon-trash"></span> Yes</button>
			</div>
		</div>
	</div>
</div>
edit.php
//edit.php
<?php
	include('conn.php');
    $data = json_decode(file_get_contents("php://input"));

    $out = array('error' => false);

    $name = $data->name;
    $position = $data->position;
    $office = $data->office;
    $id = $data->id;

   	$sql = "UPDATE employee SET name = '$name', position = '$position', office = '$office' WHERE id = '$id'";
   	$query = $conn->query($sql);

   	if($query){
   		$out['message'] = 'Employee updated Successfully';
   	}
   	else{
   		$out['error'] = true;
   		$out['message'] = 'Cannot update';
   	}

    echo json_encode($out);
?>
delete.php
//delete.php
<?php
	include('conn.php');
    $data = json_decode(file_get_contents("php://input"));

    $out = array('error' => false);

    $id = $data->id;

   	$sql = "DELETE FROM employee WHERE id = '$id'";
   	$query = $conn->query($sql);

   	if($query){
   		$out['message'] = 'Employee deleted Successfully';
   	}
   	else{
   		$out['error'] = true;
   		$out['message'] = 'Cannot delete';
   	}

    echo json_encode($out);
?>
add.php
//add.php
<?php
    include('conn.php');
    $data = json_decode(file_get_contents("php://input"));

    $out = array('error' => false, 'name' => false, 'position' => false, 'office' => false);

    $name = $data->name;
    $position = $data->position;
    $office = $data->office;

    if(empty($name)){
        $out['name'] = true;
        $out['message'] = 'name is required'; 
    } 
    elseif(empty($position)){
        $out['position'] = true;
        $out['message'] = 'position is required'; 
    }
    elseif(empty($office)){
        $out['office'] = true;
        $out['message'] = 'office is required'; 
    }
    else{
        $sql = "INSERT INTO employee (name, position, office, age, salary) VALUES ('$name', '$position', '$office', '25', '99')";
        $query = $conn->query($sql);

        if($query){
            $out['message'] = 'New Employee Added Successfully';
        }
        else{
            $out['error'] = true;
            $out['message'] = 'Cannot Add';
        }
    }
        
    echo json_encode($out);
?>
style.css
//style.css
.gray{
	color:gray;
}

.input-error{
	font-size:12px;
	color:#f44336;
}

.myModal{
	position:fixed;
	top:0;
	left:0;
	right:0;
	bottom:0;
	background: rgba(0, 0, 0, 0.4);
	z-index:100;
}

.modalContainer{
	width: 555px;
	background: #FFFFFF;
	margin:auto;
	margin-top:10px;
}

.modalHeader{
	padding:10px;
	background: #008CBA;
	color: #FFFFFF;
	height:50px;
	font-size:20px;
	padding-left:15px;
}

.editHeader{
	padding:10px;
	background: #4CAF50;
	color: #FFFFFF;
	height:50px;
	font-size:20px;
	padding-left:15px;
}

.deleteHeader{
	padding:10px;
	background: #f44336;
	color: #FFFFFF;
	height:50px;
	font-size:20px;
	padding-left:15px;
}

.modalBody{
	padding:30px;
}

.modalFooter{
	height:36px;
}

.footerBtn{
	margin-right:10px;
	margin-top:-9px;
}

.closeBtn{
	background: #008CBA;
	color: #FFFFFF;
	border:none;
}

.closeEditBtn{
	background: #4CAF50;
	color: #FFFFFF;
	border:none;
}

.closeDelBtn{
	background: #f44336;
	color: #FFFFFF;
	border:none;
}

Related Post