Building a Customer Management App Using AngularJS and Laravel (PART TWO)!

On April 9, 2014 by aTutorMe

[THIS IS OUTDATED! I’M KEEPING IT HERE FOR HISTORICAL PURPOSES :). MOVE ONTO ANGULAR 2 AND LARAVEL 5!]

Single page apps with AngularJS are quite powerful, especially when you can consume a REST API.

angular-routing

I’ve been looking for some tutorials, and scotch.io [OLD BROKEN LINK] scotch.io [GOOD LINK] definitely have a super collection of tutorials and written in a well-thought out way for beginners and are beautifully presented.

I wanted a little more practice with Laravel and AngularJS, so I googled around and found this: Building a Customer Management App Using AngularJS and Laravel.

The tutorial is only half finished, and lots of people were complaining about it! So I thought of finding out how to complete it.

I had been googling around for CRUD stuff a few months ago and came across this: CRUD Grid Using AngularJS, WebAPI, Entity Framework (EF), Bootstrap, which was written for ASP.NET WebAPI, so I decided to port it for Laravel.

So, if you’ve already completed Part 1 of the tutorial on tutsplus, then there’s not much more you have to do!

Note that the steps below create an AngularJS CRUD for the customers table only.  I have not added functionality for the transactions table.

Step 1 – Modify your CustomerController.php – add a handler for the put method

public function putIndex() {
 $id = Input::get('id');

 if (Input::has('id', 'first_name', 'last_name', 'email')) {
 $input = Input::all();
 if ($input['first_name'] == '' || $input['last_name'] == '' || $input['email'] == '') {
 return Response::make('You need to fill all of the input fields', 400);
 }
 $customer = Customer::find($id);
 $customer->first_name = $input['first_name'];
 $customer->last_name = $input['last_name'];
 $customer->email = $input['email'];
$customer->save();

 return $customer;
 } else {
 return Response::make('You need to fill all of the input fields', 400);
 }
 }

Step 2 – AngularJS CRUD interface – create index.html as follows

<!doctype html> 
<html ng-app="app"> 
<head>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.0-beta.5/angular.min.js"></script>
<script src="http://cdnjs.cloudflare.com/ajax/libs/toastr.js/2.0.0/js/toastr.min.js"></script>
<!-- Latest compiled and minified CSS -->
<link rel="stylesheet" href="http://netdna.bootstrapcdn.com/bootstrap/3.1.1/css/bootstrap.min.css">
<!-- Optional theme -->
<link rel="stylesheet" href="http://netdna.bootstrapcdn.com/bootstrap/3.1.1/css/bootstrap-theme.min.css">
<!-- Latest compiled and minified JavaScript -->
<script src="http://netdna.bootstrapcdn.com/bootstrap/3.1.1/js/bootstrap.min.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/toastr.js/2.0.1/css/toastr.css">
<title>AngularJS-WebApi-EF</title>
</head> 
<body> 
 <div ng-controller="IndexCtrl" ng-cloak> 
 <div style="width: 500px;"> 
 <table class="table table-striped table-bordered table-condensed table-hover"> 
 <tr> 
 <th style="width: 100px;"> 
 <div class="btn-toolbar"><i class="glyphicon glyphicon-plus" ng-click="toggleAddMode()"></i></div> 
 </th> 
 <th style="width: 50px;">Id</th> 
 <th>First Name</th>
 <th>Last Name</th>
 <th>Email</th>
 </tr> 
 <tr ng-show="addMode"> 
 <td> 
 <div class="btn-toolbar"> 
 <div class="btn-group"> 
 <i class="glyphicon glyphicon-save" ng-click="addCustomer()"></i> 
 <i class="glyphicon glyphicon-remove" ng-click="toggleAddMode()"></i> 
 </div> 
 </div> 
 </td> 
 <td></td> 
 <td> 
 <input ng-model="customer.first_name" /></td>
 <td>
 <input ng-model="customer.last_name" /></td> 
 <td>
 <input ng-model="customer.email" /></td> 
 </tr> 
 <tr ng-repeat="customer in customers | orderBy:'id':true"> 
 <td> 
 <div class="btn-toolbar" ng-show="customer.editMode == null || customer.editMode == false"> 
 <div class="btn-group"> 
 <i class="glyphicon glyphicon-edit" ng-click="toggleEditMode(customer)"></i> 
 <i class="glyphicon glyphicon-trash" ng-click="deleteCustomer(customer)"></i> 
 </div> 
 </div> 
 <div class="btn-toolbar" ng-show="customer.editMode == true"> 
 <div class="btn-group"> 
 <i class="glyphicon glyphicon-save" ng-click="updateCustomer(customer)"></i> 
 <i class="glyphicon glyphicon-remove" ng-click="toggleEditMode(customer)"></i> 
 </div> 
 </div> 
 </td> 
 <td>{{customer.id}}</td> 
 <td> 
 <span ng-show="customer.editMode == null || customer.editMode == false">{{customer.first_name}}</span> 
 <input ng-model="customer.first_name" ng-show="customer.editMode == true" />
 </td>
 <td>
 <span ng-show="customer.editMode == null || customer.editMode == false">{{customer.last_name}}</span> 
 <input ng-model="customer.last_name" ng-show="customer.editMode == true" />
 </td>
 <td>
 <span ng-show="customer.editMode == null || customer.editMode == false">{{customer.email}}</span> 
 <input ng-model="customer.email" ng-show="customer.editMode == true" />
 </td> 
 </tr> 
 </table> 
 </div> 
 </div> 

 <script> 
 var app = angular.module('app', []); 

 var url = 'http://localhost/tutsplus/public/customers'; 

 app.factory('customerFactory', function ($http) { 
 return { 
 getCustomers: function () { 
 return $http.get(url + '/all'); 
 }, 
 addCustomer: function (customer) { 
 return $http.post(url, customer); 
 }, 
 deleteCustomer: function (customer) { 
 return $http.delete(url + '?id=' + customer.id); 
 }, 
 updateCustomer: function (customer) { 
 return $http.put(url + '?id=' + customer.id, customer); 
 } 
 }; 
 }); 

 app.factory('notificationFactory', function () { 

 return { 
 success: function () { 
 toastr.success("Success"); 
 }, 
 error: function (text) { 
 toastr.error(text, "Error!"); 
 } 
 }; 
 }); 

 app.controller('IndexCtrl', function ($scope, customerFactory, notificationFactory) { 
 $scope.customers = []; 
 $scope.addMode = false; 

 $scope.toggleAddMode = function () { 
 $scope.addMode = !$scope.addMode; 
 }; 

 $scope.toggleEditMode = function (customer) { 
 customer.editMode = !customer.editMode; 
 }; 

 var getCustomersSuccessCallback = function (data, status) { 
 $scope.customers = data; 
 }; 

 var successCallback = function (data, status, headers, config) { 
 notificationFactory.success(); 

 return customerFactory.getCustomers().success(getCustomersSuccessCallback).error(errorCallback); 
 }; 

 var successPostCallback = function (data, status, headers, config) { 
 successCallback(data, status, headers, config).success(function () { 
 $scope.toggleAddMode(); 
 $scope.customer = {}; 
 }); 
 }; 

 var errorCallback = function (data, status, headers, config) { 
 notificationFactory.error(data.ExceptionMessage); 
 }; 

 customerFactory.getCustomers().success(getCustomersSuccessCallback).error(errorCallback); 

 $scope.addCustomer = function () { 
 customerFactory.addCustomer($scope.customer).success(successPostCallback).error(errorCallback); 
 }; 

 $scope.deleteCustomer = function (customer) { 
 customerFactory.deleteCustomer(customer).success(successCallback).error(errorCallback); 
 }; 

 $scope.updateCustomer = function (customer) { 
 customerFactory.updateCustomer(customer).success(successCallback).error(errorCallback); 
 }; 
 }); 
 </script> 
</body> 
</html>

The HTML file above is self-contained and integrates the AngularJS controller and models in one file.  Usually it is better coding style to separate the files into the MVC (Model view controller) approach.

Here is what the final product looks like!

Screen Shot 2014-04-09 at 3.31.31 pm Screen Shot 2014-04-09 at 3.31.08 pm Screen Shot 2014-04-09 at 3.30.52 pm Screen Shot 2014-04-09 at 3.30.41 pm Screen Shot 2014-04-09 at 3.30.24 pm Screen Shot 2014-04-09 at 3.30.11 pm

Special thanks to Chris Sevilleja, Eduardo Pires and Maciej Sopyło for top tutorials and contributions!