How to set a variable from an $http call then use it in the rest of the application WITHOUT making the whole application asynchronous

后端 未结 4 1834
伪装坚强ぢ
伪装坚强ぢ 2021-01-23 09:05

I have this data

{
  \"config\": {
    \"RESTAPIURL\": \"http://myserver/myrestsite\"
  }
}

and I have this factory that reads that data

4条回答
  •  耶瑟儿~
    2021-01-23 09:53

    I see you haven't used any $resource's here, but I'm hoping you have a good understanding of them:

    in factories/delay-resource.js:

    'use strict'
    
    angular.module('myApp').factory('delayResource', ['$resource', '$q',
    function($resource, $q){
        var _methods = ['query', 'get', 'delete', 'remove', 'save'];
    
        var shallowClearAndCopy = function(src, dst) {
                dst = dst || {};
    
                angular.forEach(dst, function(value, key){
                    delete dst[key];
                });
    
                for (var key in src) {
                    if (src.hasOwnProperty(key) && !(key.charAt(0) === '$' && key.charAt(1) === '$')) {
                        dst[key] = src[key];
                    }
                }
    
                return dst;
            }
    
        var delayResourceFactory = function(baseUrlPromise, url, paramDefaults){
            var _baseUrlPromise = baseUrlPromise,
                _url = url,
                _paramDefaults = paramDefaults;
    
            var DelayResource = function(value){
                shallowClearAndCopy(value || {}, this);
            };
    
            _methods.forEach(function(method){
                DelayResource[method] = function(params, successCB, errCB, progressCB){
                    if (angular.isFunction(params)) {
                        progressCB = successCB;
                        errCB = errHandlers;
                        successCB = params;
                        errHandlers = params = null;
                    }
                    else if (!params || angular.isFunction(params)){
                        progressCB = errCB;
                        errCB = successCB;
                        successCB = errHandlers;
                        params = {};
                    }
    
                    var _makeResultResource = function(url){
                        var promise = $resource(url, _paramDefaults)[method](params);
    
                            (promise.$promise || promise).then(
                                function successHandler(){
                                    var data = arguments[0];
    
                                    if (isInstance){
                                        if (angular.isArray(data))
                                            for (var i = 0; i < data.length; i++)
                                                data[i] = new DelayResource(data[i])
                                        else if (angular.isObject(data))
                                            data = new DelayResource(data)
                                    }
    
                                    successCB.apply(successCB, arguments)
                                    resultDelay.resolve.apply(resultDelay.resolve, arguments)
                                },
                                function(err){
                                    errCB.apply(errCB, arguments)
                                    resultDelay.reject.apply(resultDelay.reject, args)
                                },
                                function(){
                                    progressCB.apply(progressCB, arguments)
                                    resultDelay.notify.apply(resultDelay.notify, arguments)
                                }
                            )
                    }
    
                    var isInstance = this instanceof DelayResource,
                        resultDelay = $q.defer();
    
                    if (!angular.isString(_baseUrlPromise) && angular.isFunction(_baseUrlPromise.then))
                        _baseUrlPromise.then(
                            function successCb(apiObj){
                                _makeResultResource(apiObj.RESTAPIURL + _url)
                            },
                            function successCb(){
                                throw 'ERROR - ' + JSON.stringify(arguments, null, 4)
                            })
                    else
                        _makeResultResource(_baseUrlPromise.RESTAPIURL + _url);
    
                    return resultDelay.promise;
                };
    
    
                DelayResource.prototype['$' + method] = function(){
                    var value = DelayResource[method].apply(DelayResource[method], arguments);
                    return value.$promise || value;
                }
            });
    
            return DelayResource;
        }
    
        return delayResourceFactory;
    }]);
    

    This will be the base factory that all requests to that REST API server will go through.

    Then we need a factories/api-resource.js:

    angular.module('myApp').factory('apiResource', ['delayResource', 'api', function (delayResource, api) {
        return function (url, params) {
            return delayResource(api.URL(), url, params);
        };
    }])
    

    Now all factories created will just have to call the apiResource to get a handle on a resource that will communicate with the REST API

    Then in a file like factories/account-factory.js

    angular.module('myApp').factory('AuthRoute', ['apiResource', 'api', function (apiResource, api) {
         return apiResource(api.AUTH);
    }]);
    

    Now in factories/auth-service.js:

    'use strict';
    
    angular.module('myApp').factory('AuthService', ['$q', 'AuthRoute', 'NotificationService', function ($q, AuthRoute, api, NotificationService) {
        function _get(creds) {
            var deferred = $q.defer();
    
            AuthRoute.get()
                .then(
                    function successCb(results){
                        deferred.resolve(results);
                    },
                    function errCb(){
                        // cant remember what comes into this function
                        // but handle your error appropriately here
    
                        //NotificationService.redirect(status);
                        //deferred.reject(data, status);
                    }
                );
    
            return deferred.promise;
        }
    
        return {
            get:_get
        };
    }]);
    

    As you can imagine, I haven't been able to test it yet, but this is the basis. I'm going to try create a scenario that will allow me to test this. In the mean time, feel free to ask questions or point out mistakes made

    Late Addition Forgot to add this:

    'use strict';
    
    angular.module('myApp').factory('api', ["$http", "$q", function ($http, $q) {
      var restApiObj,
          promise;
    
      function _getConfiguration() {
        if (restApiObj)
          return restApiObj;
    
        if (promise)
          return promise;
    
        promise = $http.get('/scripts/constants/config.json')
            .then(function (data) {
              restApiObj = data;
              promise = null;
              return data;
            },
            function (data, status) {
              restApiObj = null;
              promise = null;
            });
        return promise;
      }
    
      return {
        URL: _getConfiguration
      }
    }]);
    

    Continuing with the ui-router scenario

    .state('member-list', {
        url: '/members?limit=&skip='
        templateUrl: '/views/members/list.html',
        controller: 'MemberListCtrl',
        resolve:{
          members: ['$stateParams', 'MembersLoader', function($stateParams,MembersLoader){
            return MembersLoader({skip: $stateParams.skip || 0, limit: $stateParams.limit || 10});
          }       
        }
     });
    

    factory

    .factory('MemberRoute', ['apiResource', function(apiResource){
        return apiResource('/members/:id', { id: '@id' });
    }])
    .factory('MembersLoader', ['MembersRoute', function(MembersRoute){
        return function(params){
            return MemberRoute.query(params);
        };
    }])
    .factory('MemberFollowRoute', ['apiResource', 'api', function(apiResource, api){
        return apiResource(api.FOLLOW_MEMBER, { id: '@id' });
    }])
    

    controller

    .controller('MemberListCtrl', ['$scope', 'members', 'MemberRoute', 'MemberFollowRoute', function($scope, members, MemberRoute, MemberFollowRoute){
        $scope.members = members;
    
        $scope.followMember = function(memberId){
            MemberFollowRoute.save(
                { id: memberId },
                function successCb(){
                    //Handle your success, possibly with notificationService
                },
                function errCb(){
                    // error, something happened that doesn't allow you to follow memberId
                    //handle this, possibly with notificationService
                }
            )
        };
    
        $scope.unfollowMember = function(memberId){
            MemberFollowRoute.delete(
                { id: memberId },
                function successCb(){
                    //Handle your success, possibly with notificationService
                },
                function errCb(){
                    // error, something happened that doesn't allow you to unfollow memberId
                    //handle this, possibly with notificationService
                }
            )
        };
    }]);
    

    With all this code above, you will never need to do any sort of initialization on app start, or in some abstract root state. If you were to destroy your API config every 5 mins, there would be no need to manually re-initialize that object and hope that something isn't busy or in need of it while you fetch the config again.

    Also, if you look at MembersRoute factory, the apiResource abstracts/obscures the api.URL() that you were hoping not to have to change everywhere. So now, you just provide the url that you want to make your request to, (eg: /members/:id or api.AUTH) and never have to worry about api.URL() again :)

提交回复
热议问题