简体   繁体   中英

Prevent route from loading until data is available in Angular

In the app I'm working on there is a situation in which data is pulled from a JSON file and is referenced in all subsequent routes. I want to ensure that a route does not load until this data is available, and if not available request it before loading the route. I'm trying to use a route resolve to accomplish this but am finding that the route will load regardless since the request to get the data returns a promise in the resolve. Here's an example of how the code for this is set up, is there a way to not load the route until the promise is resolved? I think the use of promises are throwing me off some.

Factory which pulls the data from the JSON file.

    .factory('jsonFactory', function($q, $http) {
        return {
            getFormStuff: function() {
                var deferred = $q.defer(),
                    httpPromise = $http.get('json/MasterObject.json');

                httpPromise.then(function(response) {
                    deferred.resolve(response);
                }, function(error) {
                    console.log(error);
                });

                return deferred.promise;
            }
        };
    }) 

ngRoute config with resolve that checks if Model.formStuff is available and if not attempts to get it before loading the route which needs the data.

app.config(function ($routeProvider) {
    $routeProvider.when('/someRoute', {
        controller: 'someController',
        templateUrl: 'views/someView.html',
        resolve: {
          getFormTemplate: function (Model, jsonFactory) {
            if (!Model.formStuff) {
                Model.formStuff = jsonFactory.getFormStuff();
                return Model.formStuff;
            } else {
                return Model.formStuff;
            }
        } 
    }
 })

EDIT: Adding the Model factory and controller where Model.formStuff is referenced. The Model.formStuff is dynamically added in a different controller and is not a pre-defined property...I inherited this code so not sure why it is handled like that.

angular.module('example', [])
    .factory('Model', ['$resource',
        function($resource) {
            return {
                query: function() {
                    return data;
                },
                get: function(id) {
                    return findById(id);
                },
                set: function(item) {
                    addItem(item);
                },
                put: function(item) {
                    updateItem(item);
                },
                del: function(id) {
                    removeItem(id);
                },
                getLoginUser: function(id) {
                    removeItem(id);
                },
                islogin: false
            };
        }
    ])

basic controller example showing how Model.formStuff is normally used.

angular.module(...)
  .controller("someController", function(Model) {        
    $scope.someField = Model.formStuff[0].someProp;
    var someVar = Model.formStuff.[0].otherProp;

    // bunch of other code...
  });

The code doesn't look that wrong. Please be sure to also handle the error case, otherwise the promise you return will never be rejected and the router will wait forever in case of some error. So you should call deferred.reject(error) in your error callback.

If you don't need any special processing on the data, you could directly return the promise of the $http.get() call like so:

getFormStuff = function() { 
  return $http.get('json/MasterObject.json');
}

What could possibly be the problem in your case is the controller definition. Do you inject a value named like the key in your resolve object into the controller? Otherwise the data will not be passed there...

angular.module(...)
  .controller("someController", function(getFormTemplate) {
    // do anything with the resolved data...
  });

Another suggestion: Instead of handling the caching stuff directly in the resolve block, why not creating a special service that caches the data and just resolving like so:

resolve: {
  getFormTemplate: function (MyCachingModel) {
    return MyCachingModel.promiseToTemplate()
  }
}

... and then moving the current logic into this caching service. This makes reasoning much clearer as your logic is not spread into the router config.

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