Introduction
It is a common requirement for any project to display data in some kind of tabular format. The easiest way to achieve this is by using HTML table. But soon, this gets complex as you need a way to support pagination (client-side and server-side), sorting (single & multi column), resizable columns, inline editing, filtering, etc. What the article/code snippet does, why it's useful, the problem it solves, etc.
Using the Code
First Grid Solution
The first solution we are going to look at is ng-grid
which is built for AngularJS and is the most popular Grid solution out there for Angular.
Where to Start
In this project, we will build a grid solution using Angular and ng-grid
, which hooks in to the RESTful end point running locally using NodeJS & ExpressJS. We will use basic features of Node & Express. Before jumping in, you may want to see the working code on Plunker: http://embed.plnkr.co.
Assumptions
- You already know AngularJS
- Know the basics of Grunt, Bower and Bootstrap
- Have basic knowledge about REST
- You already have node, npm, git and bower installed on your development machine
Project Structure
We will use the following Angular seed project:
https://github.com/libertyleap/angular-grunt-seed
This is the seed project which comes with a default bower and grunt build for lint, karma, watch, livereload, express server, etc.
Steps to Setup & Run Seed Project
- Clone the project:
> git clone https://github.com/backand/ng-grid-rest-simple-demo
- Rename the project from
angular-grunt-seed
to ng-grid-demo
:
> mv angular-grunt-seed ng-grid-demo
- Change the current directory to ng-grid-demo:
> cd ng-grid-demo
- Execute
npm install
so that all the Grunt dependencies are downloaded and it also runs bower install:
> npm install
- Execute
grunt
, this will start the local Node server on port 9000:
> grunt
- Open your favorite browser and go to: http://localhost:9000/:
Adding NG-Grid into Seed Project Using Bower
The easiest way to add ng-grid
to seed project is using Bower and we will cover this approach in this blog. If you are not comfortable doing this, you can do it manually, i.e., go to ng-grid
repo: http://angular-ui.github.io/ng-grid/ and copy over the required files which are covered below.
> bower install ng-grid –save-dev
Above command updates the ng-grid-demo\bower.json file to add ng-grid
as dependency.
"devDependencies": {
"ng-grid": "~2.0.12"
}
Bower will download ng-grid
locally. You can verify this by going in to the bower-components folder. You will see a new folder ng-grid inside the bower-components folder.
Hooking-up NG-Grid with View Restful Service
To utilize ng-grid
in our seed project, we need to reference two ng-grid
files. The first one is the JavaScript file and the second is the CSS for the theming of the grid. The first step will be to go into your index.html file and add both the JavaScript and the CSS files as dependency.
Open the ng-grid-demo/src/index.html file and add the following entries:
- In the
<head>
, add this CSS dependency (bower-components/ng-grid/ng-grid.css).
- In the
<body>
section, add ng-grid
’s js dependency (bower-components/ng-grid/ng-grid-2.0.12.debug.js). - We need to add the '
ngGrid
' Angular module dependency to app.js so that we can start using ng-grid
’s directives and other services.
NG-Grid Basic Example
We will look at the steps required to add the basic ng-grid
example in this section. We will explore ng-grid
’s advanced features in the coming sections.
To be able to demonstrate grid features, we need some kind of REST endpoint. For this blog post, we will use local JSON file as REST endpoint, which will serve list of open source contributors.
REST \ JSON
Create a folder json under ng-grid-demo\src folder. Create a new json file called contributors.json. This JSON file will have the following content, which will be served to UI \ ng-grid.
ng-grid-demo\src\json\contributor.json
[{
"id": "1",
"firstname": "Misko",
"lastname": "Havery",
"company": "Google",
"project": "AngularJS"
}, {
"id": "2",
"firstname": "Srini",
"lastname": "Kusunam",
"company": "LibertyLeap",
"project": "Backbone.Paginator"
}, {
"id": "3",
"firstname": "Derick",
"lastname": "Bailey",
"company": "Muted Solutions",
"project": "Backbone.Marionette"
}]
Change the Grunt build to include this json file in .build directory.
Angular Factory
Let’s create a service (gridService.js) that will return the above JSON using REST’s GET
method. This data will be returned asynchronously and we will use Promises ($q
) for this. Here is the Service code.
angular.module('angularGruntSeed')
.factory('GridService', ['$http', '$q',
function($http, $q) {
var contributorsFile = 'json/contributors.json';
var contributors = [];
function getContributors() {
var deferred = $q.defer();
$http.get(contributorsFile)
.then(function(result) {
contributors = result.data;
deferred.resolve(contributors);
}, function(error) {
deferred.reject(error);
});
return deferred.promise;
}
return {
getContributors: getContributors
};
}
]);
We will have one method called getContributors
which will use Angular’s $http
(https://docs.angularjs.org/api/ng/service/$http) to get the data from json/contributors.json file. It also uses Angular’s promise implementation $q
(https://docs.angularjs.org/api/ng/service/$q).
This is what is happening here:
- When controller calls this factory method “
getContributors
”, it will get a promise object back i.e., deferred.promise
. - When response comes back from the asynchronous
$http
call, we will resolve deferred object to return list of contributors. - If there is an error in
$http
, then we will reject the deferred object with the reason so that caller can handle it appropriately, i.e., show some kind of message back to user.
Controller
We will add “GridService
” as a dependency to “HomeController
” and call “getContributors
” method from GridService
. Response is set as “myData
” which will be used to populate ng-grid
data in view.
angular.module('angularGruntSeed')
.controller('HomeController', ['$scope', 'GridService',
function($scope, gridService) {
gridService.getContributors().then(function(data) {
$scope.myData = data;
});
$scope.gridOptions = {
data: 'myData'
};
}
]);
The above step $scope.gridOptions
is the main setup which hooks-up ng-grid
configuration to ng-grid
’s view.
View
Setting up the grid in your HTML file is really easy and just requires creating a div
, and adding a ng-grid
directive to it with the parameter being the function in the controller that we will create soon. We are also going to add a simple class onto the div
for easy styling. Change “templates\home.html” to include the following code:
<div class="gridStyle" ng-grid="gridOptions"></div>
Here, “gridOptions
” is $scope
object populated in controller.
This should get the basic ng-grid
up and running.
NG-Grid Features
In this section, we will explore different configuration options for ng-grid
. We just need to change $scope.gridOptions
in Controller
to be able to support the following features.
Column Definition
It is a common requirement for any Grid
to name column names different from the JSON name. One example above is we want to name “firstname
” to “First Name
”.
$scope.gridOptions = {
data: 'myData',
columnDefs: [{field:'id'},{field:'firstname', displayName:'First Name'},
{field:'lastname',displayName:'LastName'},{field:'company'},{field:'project'}]
};
Cell Template Example
Below is an example on how to define cell templates using string
s in ng-grid
. From the above example, we want to apply Green color to id
column with id > 1
.
$scope.gridOptions = {
data: 'myData',
columnDefs: [
{field:'id', cellTemplate: '
<div ng-class="{green: row.getProperty(col.field) > 1}">
<div class="ngCellText">{{row.getProperty(col.field)}}</div>
</div>
'}, {field:'firstname', displayName:'First Name'},
{field:'lastname', displayName:'Last Name'},
{field:'company'},{field:'project'}] };
In-line Cell Editing Example
We will explore an option to be able to edit the Grid
cell and save it to the REST service. We will demonstrate code to be able to update the “company
” cell of the contributor in Grid
.
homeController.js
We need to set enableCellEdit
property to TRUE
for the column definition.
{
field:'company',
enableCellEdit: true
}
After setting this, if you restart the node
server, you will see company
column is editable after double clicking the cell.
The next step is we want to send this updated cell info to REST backend. For this, we will use one of ng-grid
’s Event
(ngGridEventEndCellEdit
), which will broadcast after cell is edited. You can see all the available ng-grid
’s Event
s here: https://github.com/angular-ui/ng-grid/wiki/Grid-Events.
We will update the controller to have the following code:
$scope.$on('ngGridEventEndCellEdit', function(evt){
gridService.saveContributor(evt.targetScope.row.entity);
});
As you can see from the above code, we want to send the updated row information back to REST service. We need to define a new method saveContributor
in our gridService.js.
gridService.js
function saveContributor(contributor) {
$http.post('/save', contributor).success(function() {
console.log("SAVE success !!!!");
}).error(function() {
console.log("SAVE Error !!!!");
});
}
We do not have a real REST service and it is impossible to demo this as we need some kind of persistent store. You can open your browser’s developer tools and validate the above $http post
method is called with the right data.
References