Introduction
In this tip, we will see how to perform CRUD operations with $resource
angular service. We will be using localdb
to store our data and perform CRUD operations, and retrieve data using web API. In this tip, we are not going to see about web API or code first EF, we will be focusing completely on $resource
service.
You can clone the code from my github repository at <a href="https://github.com/Sudheer-Reddy/AngularWithDNet.git">https://github.com/Sudheer-Reddy/AngularWithDNet.git</a>
.
Background
CRUD operations are mapped to the HTTP protocols in the following manner:
GET
: This maps to the R(Retrieve)
part of the CRUD operation. This will be used to retrieve the required data (representation of data) from the remote resource. PUT
: This maps to the U(Update)
part of the CRUD operation. This protocol will update the current representation of the data on the remote server. POST
: This maps to the C(Create)
part of the CRUD operation. This will create a new entry for the current data that is being sent to the server. DELETE
: This maps to the D(Delete)
part of the CRUD operation. This will delete the specified data from the remote server.
$resource
is a factory which creates a resource object which lets you interact with RESTFul server side data sources. You can find great documentation here. The object has some action methods which let you perform CRUD operations.
Usage
Note: $resource
service is in a separate module ngResource
, so you need to include anglular.resource.js and add ngResource
module to your angular module dependencies.
$resource(url,{paramDefaults},{actions},{options});
url
: The webservice or web API url
to perform CRUD operations. paramDefaults
: The defaults for url
params. actions
: The action methods which map to CRUD operations. options
: It supports only one option stripTrailingSlashes
which is used to remove the trailing slashes from the url
.
Example
var students = $resource("api/StudentsApi");
On returned object, you will get the following action methods to perform CRUD operations:
{ 'get': {method:'GET'},
'save': {method:'POST'},
'query': {method:'GET', isArray:true},
'remove': {method:'DELETE'},
'delete': {method:'DELETE'} };
or you can have your own action methods as follows:
return $resource("api/StudentsApi", {}, {
query: { method: "GET", isArray: true },
create: { method: "POST" },
get: { method: "GET", url: "/api/StudentsApi?id=:id" },
remove: { method: "DELETE", url: "/api/StudentsApi?id=:id" },
update: { method: "PUT", url: "/api/StudentsApi?id=:id" }
});
and then, you can use them in your controller to perform CRUD operations:
stDataService.query();
stDataService.get({id:2});
stDataService.create(student);
stDataService.update({id:2},student);
stDataService.remove({id:2});
Using the Code
Coming to the source code attached, in this section, we will walk through creating a factory method to return $resource
object and how we can retrieve data before view is loaded using $routeProvider
resolve property and update or delete info in controllers.
stDataService.js
studentsManagement.factory("stDataService", [
"$resource",
function($resource) {
return $resource("api/StudentsApi", {}, {
query: { method: "GET", isArray: true },
create: { method: "POST" },
get: { method: "GET", url: "/api/StudentsApi?id=:id" },
remove: { method: "DELETE", url: "/api/StudentsApi?id=:id" },
update: { method: "PUT", url: "/api/StudentsApi?id=:id" }
});
}
]);
One of the best practices is to retrieve data before your view loads so that there won't be any flickers on the page due to async calls.
So let's create our module and use $routeProvider
to add routing to have SPA effect to your application.
main.js
var studentsManagement = angular.module("studentsManagement",
["ngResource", "ngCookies", "ngRoute"]).run(function ($rootScope) {
$rootScope.title = "Home";
})
.config([
"$routeProvider", "$locationProvider", function ($routeProvider, $locationProvider) {
$locationProvider.html5Mode({
enabled: true,
requireBase: false
});
$routeProvider.when("/", {
templateUrl: "/templates/Students.html",
controller: "stsController",
<code>resolve</code>: {
students: function ($q, stDataService) {
var deferred = $q.defer();
stDataService.query(function (data) {
deferred.resolve(data);
});
return deferred.promise;
}
}
}).when("/Student/:id", {
templateUrl: "/templates/StudentInfo.html",
controller: "stController",
<code>resolve</code>: {
student: function ($q, stDataService, $route) {
var deferred = $q.defer();
var id = $route.current.params.id;
stDataService.get({ id: id }, function (data) {
deferred.resolve(data);
});
return deferred.promise;
}
}
}).when("/Create", {
templateUrl: "/templates/CreateStudent.html",
controller: "stCreateController"
});
}
]);
Observe the resolve property above the highlighted text. If any of these dependencies of resolve properties are promises, the router will wait for all of them to be resolved or one to be rejected before the controller is instantiated. You can see above I haven't used stDataService.query();
but added a promise to get results asynchronously. It's not required, you can simply use students : stDataService.query()
.
Now let's have our controllers ready to bind scope to the view.
stsController.js:(Dashboard Page)
studentsManagement.controller("stsController", [
"$scope", "$route", "$rootScope",
"stDataService", function($scope, $route, $rootScope, stDataService) {
$rootScope.title = "Students";
$scope.students = $route.current.locals.students;
$scope.removeStudent = function(id, student) {
stDataService.remove({ id: id }).$promise.then(function() {
var index = $scope.students.indexOf(student);
$scope.students.splice(index, 1);
alertify.log(student.Name + " is removed");
});
};
}
]);
$route
service is used to access the route
params, locals
properties that we have set in routing.
The resolve property students
is accessed using $route.current.locals.students
.
stController.js:(Edit page)
studentsManagement.controller("stController", [
"$scope", "$route","$rootScope","stDataService","$location",
function ($scope, $route,$rootScope,stDataService,$location) {
$scope.student = $route.current.locals.student;
$rootScope.title = "Student Info -" + $scope.student.Name;
$scope.updateInfo = function(student) {
stDataService.update({ id: student.Id }, student).$promise.then(function() {
$location.url("/");
alertify.log("Updated Info");
});
};
}
]);
stCreateController.js:(Create page)
studentsManagement.controller("stCreateController", [
"$scope", "stDataService", "$rootScope","$location",
function($scope, stDataService, $rootScope,$location) {
$rootScope.title = "Create student";
$scope.saveStudent = function(student) {
stDataService.create(student).$promise.then(function () {
$location.url("/");
$("#stsNav").toggleClass("active");
$("#stCreate").removeClass("active");
alertify.log(student.Name + " added successfully.");
});
};
}
]);
I have used alertify.js to have some push notification kind of effect on the page to show messages after adding student, editing student and removing student.
Dash board page
Note: Add some entries to your localdb
such that the dashboard page won't be empty for the first time or you can use the create student
tab to add entries.
When you remove user, you get alertify style log message.
Thanks for reading.