Inventory Manager Using Angularjs Mysql Php

Last tutorial we created a database helper class for PHP RESTful API. In this tutorial we will use that database helper class to build a simple inventory/product manager application. We will add, update, delete, activate, deactivate products from inventory. Some AngularJS directives will make our job easy.
Features
- Truely single page web application
- Showcase the awesome power of angularjs directives
- Animations make the user interaction much enjoyable
- Has extensive power to build a large inventory management application over this framework
How to use
- Download the project file from the download link provided above
- Import the database file “products.sql” into MySQL database
- Add your database settings to the file “config.php”
There will be 3 directives essential for this simple application
- form-element [ Form element templates ]
- only-numbers [ This directive will restrict users from entering alphabets in a number field ]
- animate-on-change [ Animates a particular product when it is updated ]
In this project I ignored the security part of the web application. Please do add some security features before implementing into production.
Modules used
- AngularJS Bootstrap UI modal (for product edit)
- underscore.js (for some helper javascript functions)
- PHP Slim to create our data provider / API
Requirement Specification
- Add/Edit/Delete new products to inventory
- Activate/De-activate
- Filter list of products at client side
Application Structure
api [ This serves as our ReSTFul data provider ]
– libs [ The PHPSlim library ]
– v1 [ Our API version 1 ]
— .htaccess [ Converts urls to friendly urls for our API]
— dbHelper.php [ The helper functions to connect to MySQL Database ]
— config.php [ Database credentials and configurations ]
— index.php [ The starting point of the API ]
app
– app.js [ The starting point of our AngularJS web application ]
– productsCtrl.js [ Products are controlled from here ]
– data.js [ The middleware to connect to our API]
– directives.js [ Some essential AngularJS directives ]
css
– bootstrap.min.css
– custom.css
– font-awesome.min.css
js [ Required javascript libraries for application]
– angular.min.js
– angular-route.min.js
– angular-animate.min.js
– bootstrap.min.js
– jquery.min.js
– ui-bootstrap-tpls-0.11.2.min.js
– underscore.min.js
partials [ Partial pages for products list and product edit ]
– products.html [ List of products ]
– productEdit.html [ Product edit template ]
index.php [ This page is called when our application starts and everything starts from here ]
Let's use our database helper function and create the API for database interactions
- api/v1/dbHelper.php – Database helper functions created in previous tutorial for database access
- api/v1/config.php – Database configurations [userid, password, server name]
- api/v1/index.php – Select, Add, update, delete products
api/v1/index.php
<?php | |
require '.././libs/Slim/Slim.php'; | |
require_once 'dbHelper.php'; | |
\Slim\Slim::registerAutoloader(); | |
$app = new \Slim\Slim(); | |
$app = \Slim\Slim::getInstance(); | |
$db = new dbHelper(); | |
/** | |
* Database Helper Function templates | |
*/ | |
/* | |
select(table name, where clause as associative array) | |
insert(table name, data as associative array, mandatory column names as array) | |
update(table name, column names as associative array, where clause as associative array, required columns as array) | |
delete(table name, where clause as array) | |
*/ | |
// Products | |
$app->get('/products', function() { | |
global $db; | |
$rows = $db->select("products","id,sku,name,description,price,mrp,stock,image,packing,status",array()); | |
echoResponse(200, $rows); | |
}); | |
$app->post('/products', function() use ($app) { | |
$data = json_decode($app->request->getBody()); | |
$mandatory = array('name'); | |
global $db; | |
$rows = $db->insert("products", $data, $mandatory); | |
if($rows["status"]=="success") | |
$rows["message"] = "Product added successfully."; | |
echoResponse(200, $rows); | |
}); | |
$app->put('/products/:id', function($id) use ($app) { | |
$data = json_decode($app->request->getBody()); | |
$condition = array('id'=>$id); | |
$mandatory = array(); | |
global $db; | |
$rows = $db->update("products", $data, $condition, $mandatory); | |
if($rows["status"]=="success") | |
$rows["message"] = "Product information updated successfully."; | |
echoResponse(200, $rows); | |
}); | |
$app->delete('/products/:id', function($id) { | |
global $db; | |
$rows = $db->delete("products", array('id'=>$id)); | |
if($rows["status"]=="success") | |
$rows["message"] = "Product removed successfully."; | |
echoResponse(200, $rows); | |
}); | |
function echoResponse($status_code, $response) { | |
global $app; | |
$app->status($status_code); | |
$app->contentType('application/json'); | |
echo json_encode($response,JSON_NUMERIC_CHECK); | |
} | |
$app->run(); | |
?> |
Now our API is ready. Lets start building our application. In our index.html (start page) of our application we will put the follwing div where all the partial pages will be served.
<div id="ng-view" ng-view=""></div>
partials/products.html
Now we will display the list of products and add some simple animations for product change, the angular way
Products
<h4 class="blog-post-title">Products</h4> | |
<hr/> | |
<button type="button" class="btn btn-danger fa fa-plus" ng-click="open(product);"> Add New Product</button> | |
<div class="table-responsive"> | |
<div class="panel panel-primary"> | |
<div class="panel-heading">List of products | |
<div class="sw-search" > | |
<div class="nav-search" id="nav-search"> | |
Filter: <span class="input-icon"> | |
<input placeholder="Filter products list ..." class="nav-search-input" ng-model="filterProduct" ng-change="resetLimit();" autocomplete="off" type="text" style="width:300px;" focus> | |
<i class="search-icon fa fa-search nav-search-icon"></i> | |
</span> | |
</div> | |
</div> | |
</div> | |
<div class="panel-body"> | |
<table class="table table-striped"> | |
<tr ng-show="products.length==0"><td style="vertical-align:middle;"><i class="fa fa-ban fa-3x"></i> No data found</td></tr> | |
<tr ng-hide="products.length>-1"><td style="vertical-align:middle;"><i class="fa fa-cog fa-3x fa-spin"></i> Loading</td></tr> | |
<tr><th ng-repeat="c in columns">{{c.text}}</th></tr> | |
<tr ng-repeat="c in products | filter:filterProduct | orderBy:'-id'" id="{{c.id}}" animate-on-change='c.packing + c.stock + c.price + c.description' ng-animate=" 'animate'"> | |
<td>{{c.id}}</td><td>{{c.name}}</td><td>{{c.price}}</td><td>{{c.stock}}</td><td>{{c.packing}}</td><td>{{c.description}}</td> | |
<td> | |
<button class="btn" ng-class="{Active:'btn-success', Inactive:''}[c.status]" ng-click="changeProductStatus(c);">{{c.status}}</button> | |
</td> | |
<td style="width:100px"> | |
<div class="btn-group"> | |
<button type="button" class="btn btn-default fa fa-edit" ng-click="open(c);"></button> | |
<button type="button" class="btn btn-danger fa fa-trash-o" ng-click="deleteProduct(c);"></button> | |
</div> | |
</td> | |
</tr> | |
</table> | |
</div> | |
</div> | |
</div> | |
partials/productEdit.html
We are successful displaying the products which has got activate/deactivate and delete button. We are going to embed our products into textboxes for editing
<button type="button" class="close" ng-click="cancel();"> | |
<i class="fa fa-times-circle-o" style="margin:10px;color:blue;"></i> | |
</button> | |
<div class="modal-header"> | |
<h3 class="modal-title">Edit product [ID: {{product.id}}]</h3> | |
</div> | |
<div class="modal-body"> | |
<form name="product_form" class="form-horizontal" role="form" novalidate> | |
<form-element label="NAME" mod="product"> | |
<input type="text" class="form-control" name="name" placeholder="NAME" ng-model="product.name" ng-disabled="product.id" focus/> | |
</form-element> | |
<form-element label="DESCRIPTION" mod="product"> | |
<textarea class="form-control" name="description" placeholder="DESCRIPTION" ng-model="product.description">{{product.description}}</textarea> | |
</form-element> | |
<form-element label="PRICE" mod="product"> | |
<input type="text" name="price" class="form-control" placeholder="PRICE" ng-model="product.price" only-numbers/> | |
<small class="errorMessage" ng-show="product_form.price.$dirty && product_form.price.$invalid"> Enter the price.</small> | |
</form-element> | |
<form-element label="STOCK" mod="product"> | |
<input type="text" name="stock" class="form-control" placeholder="STOCK" ng-model="product.stock" only-numbers/> | |
<small class="errorMessage" ng-show="product_form.stock.$dirty && product_form.stock.$invalid"> Enter the available stock.</small> | |
</form-element> | |
<form-element label="PACKING" mod="product"> | |
<input type="text" name="packing" class="form-control" placeholder="PACKING" ng-model="product.packing"/> | |
<small class="errorMessage" ng-show="product_form.packing.$dirty && product_form.packing.$invalid"> Enter the Packing.</small> | |
</form-element> | |
<div class="space"></div> | |
<div class="space-4"></div> | |
<div class="modal-footer"> | |
<form-element label=""> | |
<div class="text-right"> | |
<a class="btn btn-sm" ng-click="cancel()"><i class="ace-icon fa fa-reply"></i>Cancel</a> | |
<button ng-click="saveProduct(product);" | |
ng-disabled="product_form.$invalid || enableUpdate" | |
class="btn btn-sm btn-primary" | |
type="submit"> | |
<i class="ace-icon fa fa-check"></i>{{buttonText}} | |
</button> | |
</div> | |
</form-element> | |
</div> | |
</form> | |
</div> |
All the above partial pages will be controlled by our controller productsCtrl
. Here we put the business logic of adding, deleting, updating products as well as the user interactions
app.controller('productsCtrl', function ($scope, $modal, $filter, Data) { | |
$scope.product = {}; | |
Data.get('products').then(function(data){ | |
$scope.products = data.data; | |
}); | |
$scope.changeProductStatus = function(product){ | |
product.status = (product.status=="Active" ? "Inactive" : "Active"); | |
Data.put("products/"+product.id,{status:product.status}); | |
}; | |
$scope.deleteProduct = function(product){ | |
if(confirm("Are you sure to remove the product")){ | |
Data.delete("products/"+product.id).then(function(result){ | |
$scope.products = _.without($scope.products, _.findWhere($scope.products, {id:product.id})); | |
}); | |
} | |
}; | |
$scope.open = function (p,size) { | |
var modalInstance = $modal.open({ | |
templateUrl: 'partials/productEdit.html', | |
controller: 'productEditCtrl', | |
size: size, | |
resolve: { | |
item: function () { | |
return p; | |
} | |
} | |
}); | |
modalInstance.result.then(function(selectedObject) { | |
if(selectedObject.save == "insert"){ | |
$scope.products.push(selectedObject); | |
$scope.products = $filter('orderBy')($scope.products, 'id', 'reverse'); | |
}else if(selectedObject.save == "update"){ | |
p.description = selectedObject.description; | |
p.price = selectedObject.price; | |
p.stock = selectedObject.stock; | |
p.packing = selectedObject.packing; | |
} | |
}); | |
}; | |
$scope.columns = [ | |
{text:"ID",predicate:"id",sortable:true,dataType:"number"}, | |
{text:"Name",predicate:"name",sortable:true}, | |
{text:"Price",predicate:"price",sortable:true}, | |
{text:"Stock",predicate:"stock",sortable:true}, | |
{text:"Packing",predicate:"packing",reverse:true,sortable:true,dataType:"number"}, | |
{text:"Description",predicate:"description",sortable:true}, | |
{text:"Status",predicate:"status",sortable:true}, | |
{text:"Action",predicate:"",sortable:false} | |
]; | |
}); | |
app.controller('productEditCtrl', function ($scope, $modalInstance, item, Data) { | |
$scope.product = angular.copy(item); | |
$scope.cancel = function () { | |
$modalInstance.dismiss('Close'); | |
}; | |
$scope.title = (item.id > 0) ? 'Edit Product' : 'Add Product'; | |
$scope.buttonText = (item.id > 0) ? 'Update Product' : 'Add New Product'; | |
var original = item; | |
$scope.isClean = function() { | |
return angular.equals(original, $scope.product); | |
} | |
$scope.saveProduct = function (product) { | |
product.uid = $scope.uid; | |
if(product.id > 0){ | |
Data.put('products/'+product.id, product).then(function (result) { | |
if(result.status != 'error'){ | |
var x = angular.copy(product); | |
x.save = 'update'; | |
$modalInstance.close(x); | |
}else{ | |
console.log(result); | |
} | |
}); | |
}else{ | |
product.status = 'Active'; | |
Data.post('products', product).then(function (result) { | |
if(result.status != 'error'){ | |
var x = angular.copy(product); | |
x.save = 'insert'; | |
x.id = result.data; | |
$modalInstance.close(x); | |
}else{ | |
console.log(result); | |
} | |
}); | |
} | |
}; | |
}); |

Most Popular Posts
- ShopNx - The assistant manager for influencers
- Frontendfun marketplace for software projects
- Complete steps to configure elasticsearch on Ubuntu
- Configure Vultr for Nodejs Deployment
- Appointment Booking Microservice using Javascript Fullstack
- 100+ most effective ways to promote a new blog for free
- Steps to Configure Digital Ocean Droplet for Nodejs Application Deployment
- Appointment Booking using Angularjs, Nodejs, Mongodb
- Send email with PDF attachment using PHP
- Simple task manager application using Angularjs PHP Mysql
- Steps to Configure Amazon EC2 for Nodejs app deployment
- Inventory Manager Using Angularjs Mysql Php
- User authentication using Angularjs, PHP, Mysql
- Demo of a simple CRUD Restful php service used with Angularjs and Mysql
- Simple file upload example using Angularjs
- Generate PDF using PHP from Mysql database
- Creating REST API using Nodejs and consuming in Angularjs
- Simple project demonstrates how to send email using Nodejs
- Voting system similar to stackoverflow using Angularjs PHP and Mysql
- Angularjs datagrid paging, sorting, filter using PHP and Mysql
- Useful database helper class to generate CRUD statements using PHP and Mysql
- Online Shopping Mega Menu using Angularjs, PHP, Mysql
- How to create a facebook style autocomplete using Angularjs
- Steps configuring PHP Cron Jobs - Godaddy
- How to change Mysql password
- A simple Angularjs web app that converts text to url format
- Creating SWAP file on Linux