Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to properly convert controller and service from AngularJS to using ng-resource

I only started learning ng-resource recently. I'm wondering if I am on the right track when it comes to converting my regular AngularJS application to one which uses ng-resource.

This is my old home.js controller (without using ng-resource):

angular.module("HomeApp", ["BaseApp"])
    .controller("MainCtrl", ["$http", "$window", "BaseService", function($http, $window, BaseService) {

        var self = this;

        BaseService.fetch.posts(function() {
            self.posts = BaseService.posts;
            self.cerrorMessages = BaseService.cerrorMessages;
        });

        self.like = function(id, postType) {
            BaseService.like(id, postType, function() {
                self.cerrorMessages = BaseService.cerrorMessages;
            });
        };
    }]);

And this is my old base.js (BaseService):

angular.module("BaseApp", [])
    .factory("BaseService", ["$http", "$window", function($http, $window) {
        var self = this;
        self.posts = [];
        self.cerrorMessages = [];
        self.accessErrors = function(data) {
             self.cerrorMessages = [];
             for (prop in data) {
                 if (data.hasOwnProperty(prop)){
                     self.cerrorMessages.push(data[prop]);
                 }
             }
         };

        self.fetch = {
             posts: function(callback) {
                 $http.get('/posts/')
                 .then(function(response) {
                     self.posts = response.data;
                     callback();
                 }, function(response) {
                     self.accessErrors(response.data);
                     callback();
                 });
             }
         };

        self.like = function(id, postType, callback) {
            $http.post("/" + postType + "/" + id + "/like/")
            .then(function(response) {
                angular.forEach(self.posts, function(post, index, obj) {
                    if (post.id == id) {
                        post.usersVoted.push('voted');
                        post.voted=true;
                    };
                });
            }, function(response) {
                 self.accessErrors(response.data);
                 callback();
            });
        };

        return self;
    }]);

I was told that I can greatly benefit from using ng-resources since I have a RESTful backend. I tried converting the code above to start using ng-resource, and this is what I have now. This is my resources.js:

angular.module('PostsResources', ['ngResource'])

.factory('PostsFactory', function($resource) {
  return $resource('/posts/:postId', { postId:'@id' });
});

.factory('PostLikeFactory', function($resource) {
  return $resource('/posts/:postId/like', { postId:'@id' });
});

And this is my controller (home.js):

angular.module("HomePageApp", ["BaseApp", "PostsApp"])
    .controller("MainCtrl", ["$http", "$window", "BaseService", "PostsResource", "PostLikeResource", function($http, $window, BaseService, PostsResource, PostLikeResource) {

var self = this;

function loadPosts() {
    self.posts = PostsFactory.query(function(data) {},
        function(error) {
          BaseService.accessErrors(error.data);
          self.cerrorMessages = BaseService.cerrorMessages;
        }
    );
};

self.like = function likePost() {
    PostLikeFactory.save(function(data) {
        angular.forEach(self.posts, function(post, index, obj) {
            if (post.id == id) {
                post.usersVoted.push('voted');
                post.voted=true;
            };
        });
    }, function(error) {
        BaseService.accessErrors(error.data);
        self.cerrorMessages = BaseService.cerrorMessages;
    }
)};

And this is my BaseService (base.js):

angular.module("BaseApp", [])
    .factory("BaseService", ["$http", "$window", function($http, $window) {
        var self = this;
        self.posts = [];
        self.cerrorMessages = [];
        self.accessErrors = function(data) {
             self.cerrorMessages = [];
             for (prop in data) {
                 if (data.hasOwnProperty(prop)){
                     self.cerrorMessages.push(data[prop]);
                 }
             }
         };
        return self;
    }]);

Am I on the right track of converting a regular AngularJS app to using ng-resource? To me it seems like the amount of code required looks the same. Thanks in advance!

like image 362
SilentDev Avatar asked Nov 24 '15 02:11

SilentDev


2 Answers

Generally, I only use ng-resource when I have complete CRUD web applications. Example would be a CRM kind of app, where you need to create customers, update customers, delete customers and show a list of customers. It makes sense to use ng-resource as it "handles" the get, post, put, and delete HTTP methods for you.

However, in your example, it seems like the only actions you have is "Like" and "Getting a list of Posts". If you are ONLY going to use one of the HTTP methods, for each resource type, then I'd suggest just sticking to your old way of using the BaseService.

Just my 2 cents on this matter.

like image 161
Mark Avatar answered Oct 16 '22 16:10

Mark


I agree with @Mark that you probably don't have enough operations in your API to fully take advantage of $resource, so the benefits aren't as great. For what you have now though, if you're wanting to use $resource, I would set it up like this:

angular.module('PostsResources', ['ngResource'])
   .factory('Post', function($resource) {
      return $resource('/posts/:postId', { postId:'@id' }, {
         like: {
            url: '/posts/:postId/like',
            method: 'POST',
            params: { postId:'@id' }
         }
      })
   });

If you get to where you're using more than one action per endpoint, I would have a Post and PostLike resource, but in your case, that's not necessary.

In your controller, you'll be able to work with your posts like this:

self.posts = Post.query(null, BaseService.errorHandler(self));

self.like = function(post) {
   post.$like(function() {
      angular.forEach(self.posts, function(post, index, obj) {
            if (post.id == id) {
                post.usersVoted.push('voted');
                post.voted=true;
            };
        });
   }, BaseService.errorHandler(self));
};

The errorHandler method you could add to your BaseService to get rid of some duplication. It would look something like this:

self.errorHandler = function(viewModel) {
   return function(error) {
      BaseService.accessErrors(error.data);
      viewModel.cerrorMessages = BaseService.cerrorMessages;
   };
};
like image 1
DerekMT12 Avatar answered Oct 16 '22 18:10

DerekMT12