angular-js-rest-api
Simple AngularJS Front-End for a REST API
1. Overview
We’re going to display data in a table, create a resource, update it, and finally delete it.
2. The REST API
-
get paginated – *GET* /api/myFeeds?page={page}&size={size}&sortDir={dir}&sort={propertyName}
-
create – *POST* /api/myFeeds
-
update – *PUT* /api/myFeeds/{id}
-
delete – *DELETE* /api/myFeeds/{id}
A quick note here is that pagination is using the following 4 parameters:
-
page: index of requested page
-
size: maximum number of records per page
-
sort: the name of property used in sorting
-
sortDir: the sorting direction
And here’s an example of what the Feed resource looks like:
{
"id":1,
"name":"baeldung feed",
"url":"/feed"
}
3. The Feeds Page
<script
src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.14/angular.min.js">
</script>
<script
src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.14/angular-resource.min.js">
</script>
<script th:src="@{/resources/ng-table.min.js}"></script>
<script th:src="@{/resources/mainCtrl.js}"></script>
<a href="#" ng-click="addNewFeed()">Add New RSS Feed</a>
<table ng-table="tableParams">
<tr ng-repeat="row in $data track by row.id">
<td data-title="'Name'" sortable="'name'">{{row.name}}</td>
<td data-title="'Feed URL'" sortable="'url'">{{row.url}}</td>
<td data-title="'Actions'">
<a href="#" ng-click="editFeed(row) ">Edit</a>
<a href="#" ng-click="confirmDelete(row.id) ">Delete</a>
</td>
</tr>
</table>
</div>
</body>
</html>
Note that we used ng-table to display data – more on that in the following sections.
4. An Angular Controller
var app = angular.module('myApp', ["ngTable", "ngResource"]);
app.controller('mainCtrl', function($scope, NgTableParams, $resource) {
...
});
Note that:
-
We injected the ngTable module to use it for displaying our data in a user friendly table and handle pagination/sorting operations
-
We also injected ngResource module to use it for accessing our REST API resources
5. An AngularJS DataTable
$scope.feed = $resource("api/myFeeds/:feedId",{feedId:'@id'});
$scope.tableParams = new NgTableParams({}, {
getData: function(params) {
var queryParams = {
page:params.page() - 1,
size:params.count()
};
var sortingProp = Object.keys(params.sorting());
if(sortingProp.length == 1){
queryParams["sort"] = sortingProp[0];
queryParams["sortDir"] = params.sorting()[sortingProp[0]];
}
return $scope.feed.query(queryParams, function(data, headers) {
var totalRecords = headers("PAGING_INFO").split(",")[0].split("=")[1];
params.total(totalRecords);
return data;
}).$promise;
}
});
The API expects a certain style of pagination, so we need to customize that here in the table to match it. We’re using params out of ng-module and creat our own queryParams here.
A few additional notes about pagination:
-
params.page() starts from 1 so we also need to make sure it becomes zero indexed when communicating with the API
-
params.sorting() returns an object – for example \{“name”: “asc”}, so we need to separate the key and value as two different parameters – sort, sortDir
-
we extract the total element count from a HTTP header of the Response
6. More Operations
Finally, we can perform a lot of operations using ngResource module – $resource does cover the full HTTP semantics in terms of available operations. We can also define our custom functionality.
We have used query in the previous section to get the feeds list. Note that both get and query do GET – but query is used to handle an array response.
6.1. Add a New Feed
$scope.feed = {name:"New feed", url: "http://www.example.com/feed"};
$scope.createFeed = function(){
$scope.feeds.save($scope.feed, function(){
$scope.tableParams.reload();
});
}
6.2. Update a Feed
$scope.feeds = $resource("api/myFeeds/:feedId",{feedId:'@id'},{
'update': { method:'PUT' }
});
$scope.updateFeed = function(){
$scope.feeds.update($scope.feed, function(){
$scope.tableParams.reload();
});
}
Note how we configured our own update method to send out a PUT request.
7. AngularJs Dialog
Now, let’s see how to use ngDialog module to display simple form for adding/updating our feeds.
Here is our template, we can define it in a separate HTML page or in the same page:
<script type="text/ng-template" id="templateId">
<div class="ngdialog-message">
<h2>{{feed.name}}</h2>
<input ng-model="feed.name"/>
<input ng-model="feed.url"/>
</div>
<div class="ngdialog-buttons mt">
<button ng-click="save()">Save</button>
</div>
</script>
And then we will open our dialog to add/edit a feed:
$scope.addNewFeed = function(){
$scope.feed = {name:"New Feed", url: ""};
ngDialog.open({ template: 'templateId', scope: $scope});
}
$scope.editFeed = function(row){
$scope.feed.id = row.id;
$scope.feed.name = row.name;
$scope.feed.url = row.url;
ngDialog.open({ template: 'templateId', scope: $scope});
}
$scope.save = function(){
ngDialog.close('ngdialog1');
if(! $scope.feed.id){
$scope.createFeed();
} else{
$scope.updateFeed();
}
}
Note that:
-
$scope.save() is called when user clicks Save button in our dialog
-
$scope.addNewFeed() is called when user clicks Add New Feed button in feeds page – it initializes a new Feed object (without id)
-
$scope.editFeed() is called when user wants to edit a specific row in Feeds table
8. Error Handling
In order to handle server error responses globally – instead of per request – we’ll register an interceptor to the $httpProvider:
app.config(['$httpProvider', function ($httpProvider) {
$httpProvider.interceptors.push(function ($q,$rootScope) {
return {
'responseError': function (responseError) {
$rootScope.message = responseError.data.message;
return $q.reject(responseError);
}
};
});
}]);
And here’s our message representation in HTML:
<div ng-show="message" class="alert alert-danger">
{{message}}
</div>
9. Conclusion
The full implementation of this tutorial can be found in the github project – this is an Eclipse based project, so it should be easy to import and run as it is.