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 <!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; }