Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / web / HTML

CRUD Operations with $resource

4.40/5 (3 votes)
29 Mar 2015CPOL3 min read 20.3K   591  
CRUD Operations with $resource

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.

JavaScript
$resource(url,{paramDefaults},{actions},{options}); //url is required parameter.
  • 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

JavaScript
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:

JavaScript
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: 

JavaScript
stDataService.query(); // Will return array of  students
stDataService.get({id:2}); // Returns student with id 2
stDataService.create(student); //Adds new student entry
stDataService.update({id:2},student); //Updates student 2 info
stDataService.remove({id:2}); //Removes student with 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

JavaScript
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

JavaScript
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)

JavaScript
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)

JavaScript
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)

JavaScript
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.

Image 1

When you remove user, you get alertify style log message.

Image 2

Thanks for reading.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)