Introduction
Editing data in GridView
is one of the common scenarios now a days. With 2 way data binding feature of AngularJs, it became extremely easy to write code for relatively, so called, complex operations like batch editing in GridView
. This article provides you multiple approaches on how you can implement batch editing in GridView
with just few lines of code. I have also given the sample to post the updated grid data to server using WebAPI in order to save it to database.
Please note that if you are looking for a built in AngularJs GridView tool, you will get many tools with a lot of features. This article provides a native approach with just few lines of code and will help you to fulfill your custom needs. The same approach can be applied to any kind of inline editing too. An example has also been provided for inline editing in non-tabular repeat items.
This article assumes that you know the basics of AngularJs.
Below is the screenshot of basic batch editing in the application:
The below screenshot shows the second approach on batch editing:
How It Works
Batch editing in AngularJs can be implemented by using 3 simple steps:
- Get grid data from the server using API in controller
- Populate data in table row a respective control instead of directly in table cell
- On click of submit, simply submit data to the server
Step 1
To fetch data from the server is easy. You can simply use $http
/resource and assign the retrieved data to your scope variable.
Step 2
If you know about AngularJs and HTML, creating table/grid is quite easy. Just create the table
element and use ng-repeat
to populate all respective elements of each row. If you don’t want to use table
, you can very well choose any other template.
See the below sample, where model/data is directly bound to HTML control. The beauty with AngularJs is that it updates the model automatically as soon as you change the data in your HTML control.
<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>
In some scenario, you might want the controls to be shown only while editing. This gives you flexibility to keep the display format different while displaying. To achieve this, I have set up two elements for each text in grid. One appears while displaying data and another, while editing. To achieve this, I have simply used ng-show
directive and made mutually exclusive for both the controls like this:
- Display Control:
ng-show="!employee.edit.Name"
- Edit Control:
ng-show="employee.edit.Name"
The below code demonstrates this approach:
<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>
You can toggle this display based on any event. In the sample, It is being toggled in double click event.
Step 3
When the data is changed in the HTML controls, the model updated automatically. So, in this step, you don’t need to worry about collecting data from the controls. Just send the model back to the server via an API. In my example, I have used $http
to post the updated model back to the WebAPI.
Batch Editing in Non-Tabular Repeat Items
In many scenarios, we need to display the list of items as a block which repeats for each item. In such scenarios, gridview
may not be the best fit for your batch editing needs. Below is the sample on how you can simply achieve this with a few lines of code:
<div class="rpt-item pull-left col-md-4" ng-class="{'bg-gray': $index % 2 != 0}"
ng-repeat="employee in employees">
<h4>
{{$index + 1}}.
<span ng-show="!employee.edit.Name" ng-dblclick="employee.edit.Name =
!employee.edit.Name; $(this).next().focus();">{{employee.Name}}</span>
<input type="text" ng-show="employee.edit.Name" ng-blur="employee.edit.Name =
!employee.edit.Name"
ng-model="employee.Name" />
</h4>
<div ng-show="!employee.edit.BirthDate" ng-dblclick="employee.edit.BirthDate =
!employee.edit.BirthDate">
<strong>DOB:</strong> {{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="bs-datepicker" />
<div ng-show="!employee.edit.Salary" ng-dblclick="employee.edit.Salary =
!employee.edit.Salary">
<strong>Salary:</strong> {{employee.Salary | currency}}
</div>
<input type="number" ng-show="employee.edit.Salary"
ng-blur="employee.edit.Salary = !employee.edit.Salary"
ng-model="employee.Salary" />
<div ng-show="!employee.edit.Address" ng-dblclick="employee.edit.Address =
!employee.edit.Address">
<strong>Address:</strong> {{employee.Address}}
</div>
<input type="text" ng-show="employee.edit.Address"
ng-blur="employee.edit.Address = !employee.edit.Address"
ng-model="employee.Address" />
<div ng-show="!employee.edit.Country" ng-dblclick="employee.edit.Country =
!employee.edit.Country">
<strong>Country:</strong> {{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>
</div>
The approach for batch edit is quite similar here as in tabular batch edit. The only difference is, instead of tr
and td
, div
is used here. Below is the output for the same:
About the Code
In this section, I have explained a bit about the way in which code is written. It will be helpful for those who are new to AngularJs.
The CSS Stuff
The best advantage of using a native approach to create a grid is, you can customize it to any extent you want. In our example, we have a textbox
, dropdown and other controls inside table cell. For appearance, border is removed and width is set to 100%.
.batch-edit input, .batch-edit select{
margin:-4px;
border:none;
width:100%;
}
The Controller
For all edit pages, single controller called employeeEditCtrl
has been used with multiple views associated with it. This controller contains only three main functions. One to populate Employee
and related data from the WebAPI. Another to set the drop-down list values based on retrieved data. And the third one is to submit the data on submit button click. For details, please have a look at the employeeEditCtrl.js file.
Misc
I have used factory to retrieve the data using $http
but you can retrieve data in any way you want. angular-ui-router.js is used for routing and navigation. I haven't used any database for simplicity. Mock DB has been used to provide the data to UI.
Points of Interest
This article also acts as a sample for displaying data in grid using AngularJS. Moreover, the code also provides the sample on how to use Angular UI routing and use date-picker
control in AngularJs.
Future Consideration
Due to lack of time, I have not provided the sample on inline editing for row-only. At a later point of time, I will also add sample on editing records as a pop-up. Moreover, in the current sample, I have added only the most commonly used editing controls like textbox, number, datetime and dropdown. In future, I will add some complex controls also.
History
- 15th October, 2014: First version