How to achieve batch editing in Angular JS

Tarun Kumar Chatterjee
 
Net – Technology Specialist
April 6, 2017
 
Rate this article
 
Views
3608

In this article let me go through the design and implementation of batch editing functionalities using angular js only.

Create a new solution named as “AngularBatchEditing”– > ASP.Net MVC4 Web Application — > Select Web API and then OK

Within the Model create Employee class which will have the following properties

 public int Id { get; set; }
         public string Name { get; set; }
         public string Address { get; set; }
         public DateTime? BirthDate { get; set; }
         public int Salary { get; set; }
         public int CountryId { get; set; }
         public Country Country { get; set; }
 
 
 

And in the Country will have the below properties

 public int Id { get; set; }
         public string Name { get; set; }
 

Add an empty WebAPI Controller named as “EmployeeController”

Run the below command to install angular JS to your application

PM> Install-Package angularjs

In one of my earlier article I already explained about to perform CRUD operation using Angular JS with WebAPI. Here also we will be doing the same thing, only difference is on UI part. So, here instead of giving details steps I am focusing on the UI designing part, remaining you can take the reference from the link: https://www.sharepointpals.com/post/How-to-create-a-SPA-MVC-CRUD-application-using-WebAPI-Angular-JS-bootstrap-Entity-framework

Layout view code:

 <!DOCTYPE html>
 <html>
 <head>
     <meta charset="utf-8" />
     <meta name="viewport" content="width=device-width, initial-scale=1.0" />
     <title>Batch Edit Application</title>
         @Styles.Render("~/Content/css")
     <link href="~/Content/batchedit.css" rel="stylesheet" />
 
           @Scripts.Render("~/bundles/modernizr")
           @Scripts.Render("~/bundles/jquery")
           @Scripts.Render("~/bundles/bootstrap")
     <script src="~/Scripts/angular.min.js"></script>
     <script src="scripts/angular-ui/angular-ui-router.js"></script>
     <script src="scripts/angular-resource.min.js"></script>
     <script src="scripts/angular-ui/ui-bootstrap-tpls.min.js"></script>
     <script src="~/Scripts/angular-strap/angular-strap.min.js"></script>
     <script src="~/Scripts/angular-strap/angular-strap.tpl.min.js"></script>
     <script src="~/Scripts/bootstrap-datepicker.js"></script>
     <script src="js/app.js"></script>
     <script src="js/factory.js"></script>
     <script src="js/employeeEditCtrl.js"></script>
     <script src="js/employeeViewCtrl.js"></script>
 </head>
 <body ng-app="employeeApp">
     <div class="navbar navbar-fixed-top">
         <div class="container">
             <div class="navbar-header">
                 <button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
                     <span class="icon-bar"></span>
                     <span class="icon-bar"></span>
                     <span class="icon-bar"></span>
                 </button>
                 @Html.ActionLink("Batch Edit App", "Index", "Home", null, new { @class = "navbar-brand" })
             </div>
             <div class="navbar-collapse collapse">
                 <ul class="nav navbar-nav">
                     <li>@Html.ActionLink("First Approach", "Index", "Home")</li>
                     <li><a ui-sref="edit2">Second Approach</a></li>
                     <li><a ui-sref="view">View Employee</a></li>
                 </ul>
             </div>
             <hr style="margin:0px;" />
         </div>
     </div>
     <div class="container body-content">
         @RenderBody()
         <hr />
         <footer>
             <p>© @DateTime.Now.Year - My ASP.NET Application</p>
         </footer>
     </div>
 
     @RenderSection("scripts", required: false)
 </body>
 </html>
 

Index.cshtml Code:

 <div>
     <div ui-view></div>
 </div>
 

EmployeeEdit.html Code:

Only single clicking on Grid row, textbox will appear to user to edit the data

 <div id="employeeEdit" ng-controller="employeeEditCtrl">
     <div class="row">
         <div class="col-md-12">
             <h2>Simple Batch Editing in AngularJs</h2>
             <hr />
 
             <table id="employeeEditTable" class="table table-bordered batch-edit">
                 <colgroup>
                     <col width="60" />
                     <col width="140" />
                     <col width="300" />
                     <col width="100" />
                     <col width="100" />
                     <col width="100" />
                 </colgroup>
                 <tr>
                     <th>S. No.</th>
                     <th>Name</th>
                     <th>Address</th>
                     <th>Date of Birth</th>
                     <th>Salary</th>
                     <th>Country</th>
                 </tr>
                 <tr ng-repeat="employee in employees">
                     <td>{{$index + 1}}.</td>
                     <td><input type="text" ng-model="employee.Name" /></td>
                     <td><input type="text" ng-model="employee.Address" /></td>
                     <td>
                         <input type="text" ng-model="employee.BirthDate" name="date" bs-datepicker />
                     </td>
                     <td class="text-right">
                         <input type="number" class="text-right" ng-model="employee.Salary" />
                     </td>
                     <td>
                         <select ng-options="c.Name for c in countries" ng-model="employee.Country" 
                             ng-init="setDropDown(employee);" ng-change="employee.CountryId = employee.Country.Id"></select>
                     </td>
                 </tr>
             </table>
         </div>
     </div>
     <div class="row">
         <div class="col-md-12">
             <input type="button" class="btn btn-primary" value="Submit" ng-click="onSubmit();" />
         </div>
     </div>
     <div class="row">
         <div class="col-md-12">
             This page is an example of simple batch edit using angularJs by binding data to controls directly. 
 When you click on submit button, you can directly send the bound data to the server.
         </div>
     </div>
 </div>
 

employeeEdit2.html Code:

Only double clicking on Grid row textbox will appear to user to edit the data

 <div id="employeeEdit2" ng-controller="employeeEditCtrl">
     <div class="row">
         <div class="col-md-12">
             <h2>Batch Editing 2nd Approach</h2>
             <hr />
             Double click to edit
             <table id="employeeEditTable" class="table table-bordered batch-edit2">
                 <colgroup>
                     <col width="60" />
                     <col width="140" />
                     <col width="350" />
                     <col width="100" />
                     <col width="100" />
                     <col width="100" />
                 </colgroup>
                 <tr>
                     <th>S. No.</th>
                     <th>Name</th>
                     <th>Address</th>
                     <th>Date of Birth</th>
                     <th>Salary</th>
                     <th>Country</th>
                 </tr>
                 <tr ng-repeat="employee in employees">
                     <td>{{$index + 1}}.</td>
                     <td>
                         <div ng-show="!employee.edit.Name" ng-dblclick="employee.edit.Name = !employee.edit.Name">{{employee.Name}}</div>
                         <input type="text" ng-show="employee.edit.Name" ng-blur="employee.edit.Name = !employee.edit.Name" ng-model="employee.Name" />
                     </td>
                     <td>
                         <div ng-show="!employee.edit.Address" ng-dblclick="employee.edit.Address = !employee.edit.Address">{{employee.Address}}</div>
                         <input type="text" ng-show="employee.edit.Address" ng-blur="employee.edit.Address = !employee.edit.Address" ng-model="employee.Address" />
                     </td>
                     <td>
                         <div ng-show="!employee.edit.BirthDate" ng-dblclick="employee.edit.BirthDate = !employee.edit.BirthDate">{{employee.BirthDate | date:'dd MMM, yyyy'}}</div>
                         <input type="text" ng-show="employee.edit.BirthDate" ng-blur="employee.edit.BirthDate = !employee.edit.BirthDate" ng-model="employee.BirthDate" name="date" bs-datepicker />
                     </td>
                     <td class="text-right">
                         <div ng-show="!employee.edit.Salary" ng-dblclick="employee.edit.Salary = !employee.edit.Salary">{{employee.Salary | currency}}</div>
                         <input type="number" ng-show="employee.edit.Salary" ng-blur="employee.edit.Salary = !employee.edit.Salary" ng-model="employee.Salary" />
                     </td>
                     <td>
                         <div ng-show="!employee.edit.Country" ng-dblclick="employee.edit.Country = !employee.edit.Country">{{employee.Country.Name}}</div>
                         <select ng-options="c.Name for c in countries" ng-show="employee.edit.Country" ng-blur="employee.edit.Country = !employee.edit.Country" ng-model="employee.Country" ng-init="setDropDown(employee);" ng-change="employee.CountryId = employee.Country.Id"></select>
                     </td>
                 </tr>
             </table>
         </div>
     </div>
     <div class="row">
         <div class="col-md-12">
             <input type="button" class="btn btn-primary" value="Submit" ng-click="onSubmit();" />
         </div>
     </div>
     <div class="row">
         <div class="col-md-12">
             
 If you want edit controls to appear only when you double click (or other event), this approach is suitable for you.
 When you click on submit button, you can directly send the bound data to the server.
         </div>
     </div>
 </div>
 

app.js Code:

 'use strict';
 
 var app = angular.module('employeeApp', ['ui.router', 'ngResource', 'ui.bootstrap', 'mgcrea.ngStrap'])
 
       .config(['$urlRouterProvider', '$stateProvider', function ($urlRouterProvider, $stateProvider) {
           $urlRouterProvider.otherwise('/');
           $stateProvider
             .state('home', {
                 url: '/',
                 templateUrl: 'templates/employeeEdit.html',
                 controller: 'employeeEditCtrl'
             })
             .state('edit2', {
                 url: '/edit2',
                 templateUrl: 'templates/employeeEdit2.html',
                 controller: 'employeeEditCtrl'
             })
             .state('view', {
                 url: '/view',
                 templateUrl: 'templates/viewEmployee.html',
                 controller: 'employeeViewCtrl'
             })
             .state('contact', {
                 url: '/contact',
                 templateUrl: 'contact.html',
                 controller: 'quizCtrl'
             })
       }])
 .config(function ($datepickerProvider) {
     angular.extend($datepickerProvider.defaults, {
         dateFormat: 'dd MMM, yyyy',
         startWeek: 1
     });
 })
 

employeeEditCtrl.js Code:

 app.controller('employeeEditCtrl', ['$scope', '$http', 'employeeFactory', function ($scope, $http, employeeFactory) {
     
     $scope.employees;
     $scope.countries;
 
     getEmployeeData();
     
     function getEmployeeData() {
         employeeFactory.getCountries()
             .success(function (data) {
                 $scope.countries = data;
             })
             .error(function (error) {
                 $scope.status = 'Unable to load country data: ' + error;
                 console.log(error);
             });
 
         employeeFactory.getEmployees()
             .success(function (data) {
                 $scope.employees = data;
                 $scope.employees.forEach(function (emp) {
                     $scope.setDropDown(emp);
                 });
             })
             .error(function (error) {
                 $scope.status = 'Unable to load employee data: ' + error;
                 console.log(error);
             });
 
     }
 
     $scope.setDropDown = function (emp) {
         for (var index in $scope.countries) {
             if ($scope.countries[index].Id == emp.CountryId) {
                 emp.Country = $scope.countries[index];
                 return $scope.countries[index];
             }
         }
     }
 
     $scope.onSubmit = function () {
         var employees = $scope.employees;
         $http.post('api/Employee/Save', employees).success(function (data, status) {
             alert(data);
         });
     }
 }]);
 
 

factory.js Code:

 angular
   .module('employeeApp')
   .factory('employeeFactory', ['$http', function ($http) {
       var urlBase = '/api/Employee';
       var employeeFactory = {};
 
       employeeFactory.getEmployees = function () {
           return $http.get(urlBase);
       };
       employeeFactory.getCountries = function () {
           return $http.get(urlBase + '/GetCountry');
       };
 
       return employeeFactory;
   }])
 
 

In the EmployeeController, we have below Save method. After editing grid rows and clicking on Submit button, all the employee data with updated values can be captured through method parameter. Then we can do the DB operations with updated Employees data

 [HttpPost]
         [Route("api/Employee/Save")]
         public bool Save(IEnumerable<Employee> employees)
         {
             //Write your code to save your employees to database.            
             return true;
         }
 

Hope this article helps you to design a batch editing grid using angular JS and posting the all Employee data with updated values to WebAPI.

Happy Coding

Tarun Kumar Chatterjee

Author Info

Tarun Kumar Chatterjee
 
Net – Technology Specialist
 
Rate this article
 
Tarun has been working in IT Industry for over 12+ years. He holds a B-tech degree. He is passionate about learning and sharing the tricks and tips in Azure, .Net ...read more
 

Leave a comment