简体   繁体   中英

Angular.JS API using a factory

I've written a backend service which is used by a Angular.JS frontend using a factory, like so:

angular.module('app.social', ['ngResource'])
    .factory('Social', function($http) {
        return {
            me: function() {
                return $http.get('http://localhost:3000/me');
            },
            likeVideo: function(link) {
                return $http.post('http://localhost:3000/like/video', { link : link });
            },
            post: function(link) {
                return $http.post('http://localhost:3000/post', { link : link });
            },
            postVideo: function(link) {
                return $http.post('http://localhost:3000/post/video', { link : link });
            },
            friends: function() {
                return $http.get('http://localhost:3000/friends');
            },
            taggableFriends: function() {
                return $http.get('http://localhost:3000/friends/taggable');
            },
            videos: function() {
                return $http.get('http://localhost:3000/videos');
            }
        };
    });

The Social.me endpoint receives profile information from the REST backend. This function is used in various Angular controllers, however (profile page, item detail page, header account button etc.). This means that for every view, profile information is requested from http://localhost:3000/me . Is this good practice, or is it a better idea to cache the information within the factory?


EDIT: Updated code (based on answer from @Rebornix):

angular.module('app.social', ['ngResource'])
    .service('SocialService', function() {
        var serviceData = {
            me: null
        };
        return serviceData;
    })
    .factory('Social', function($http, SocialService) {
        return {
            me: function() {
                if (SocialService.me === null) {
                    return $http.get('http://localhost:3000/me').then(function(response) {
                        SocialService.me = response.data;
                        return SocialService.me;
                    });
                } else {
                    return SocialService.me;
                }
            }
        }
    };
});

In the controller, I use:

angular.module('app.profile', [])
    .controller('ProfileCtrl', ['$window', '$scope', 'Social', function($window, $scope, Social) {
        $scope.me = Social.me();
    }])

And the view:

<div ng-controller="ProfileCtrl">
    <h1 class="profile-name">{{ me.name }}</h1>
</div>

But the view is not updated as the Facebook.me value get initialized on the first request. I guess I have to manually trigger $scope.$apply() somehow?

You can create a service as storage across controllers like

angular.module('app.social', ['ngResource'])
.service("SocialService", function() {
   var info = {
     me: null,
     friends: []
   };
   return info;
})
.factory('Social', function($http, SocialService) {
    return {
        me: function() {
               $http.get('http://localhost:3000/me').then(function(response){
               SocialService.me = response.data;
               });
        },

Then in all your controllers, reference infoService instead of calling API again. What you need to is fetching latest data and refresh infoService , all controllers scope will be notified with this change.

In your controller

angular.module('app.profile', [])
    .controller('ProfileCtrl', ['$window', '$scope', 'SocialService', 'Social', function($window, $scope, SocialService, Social) {
    $scope.SocialService = SocialService;
    // Kick off social factory to update user info, you can move it into 
    // any other functions like `ng-click`.
    Social.me();
}])

Then in your view

{{SocialService.me}}
(function (app) {
'use strict';

app.factory('myService', MyService);

MyService.$inject = ['$q', 'serviceResource'];

function MyService($q, serviceResource) {
    var jobs = [];

    var service = {
        getJobs: getJobs
    };

    return service;

    //////////////////////////////////////

    function getJobs(refresh) {
        if (refresh) {
            return serviceResource.autosysJobs().$promise.then(function (data) {
                    jobs = data;
                    return jobs;
                }, function (err) {
                    throw err;
                });
        }
        else {
            var deferrer = $q.defer();
            deferrer.resolve(jobs);
            return deferrer.promise;
        }
    }
}
}(angular.module('app')));

you can pass a bool argument to tell weather to get local copy or fresh copy

It all depends upon the frequency of data change in back end data change and degree of tolerance of data inconsistency in your application. if the source data is changing too frequently and you can't afford inconsistent data then you have no choice other than to get fresh copy every time, but if that's not the case then you can cash data locally

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM