Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
181 views
in Technique[技术] by (71.8m points)

javascript - AngularJS promise is resolved before data is loaded

In my app, I have to fetch some JSON data and assign it to an array before the page is loaded. This is my code for fetching the JSON using the CardService service:

cards = [];

var cs = {
...
fetchCards: function() {
      var d = $q.defer();
      $http.get("data/cards.php").success(function(data) {
                      cards = data;
                      d.resolve();
                }).error(function(data, status) {
                      d.reject(status);        
                 });
               return d.promise;
      },
getCards: function() { return cards; };
...
}

In the controller's resolve block, I have the following:

WalletController.resolve = {
        getCards: function(CardService) {
                CardService.fetchCards().then(loadView, showError);
        }
}

And in the actual controller, I have the following:

function WalletController($scope, CardService) {
    $scope.cards = CardService.getCards();
}

The problem is, the fetchCards function in the service seems to resolve the promise before the JSON data is assigned to the cards variable. This leads to my view loading with blank data until I refresh a couple times and get lucky.

I can confirm the late loading as when I log the cards variable in the console, I get an empty array at line 122 (when my view is loaded) and a full array at line 57 (when the JSON call is successful). Line 57's code somehow executes after the view is loaded.

How do I fix this?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

I haven't used resolve but I'm throwing this out there just in case the issue you are having is related to binding to an array returned from a service.

If you are returning your cards array from a service and binding to it in the UI you may want to try to populate that same array instead of setting cards = data; (which will overwrite the local cards with a new array which is not bound to the UI).

Something like:

fetchCards: function() {
      var d = $q.defer();
      $http.get("data/cards.php").success(function(data) {
                      cards.length = 0;
                      for(var i = 0; i < data.length; i++){
                          cards.push(data[i]);
                      }
                      d.resolve();
                }).error(function(data, status) {
                      d.reject(status);        
                 });
               return d.promise;
      },

See this fiddle for a working example of what I'm trying to describe. Clicking the first button multiple times will update the view but once you click on the second button the binding will be broken.

The main difference between the two is:

  1. First button uses data.length = 0 and data.push() to retain the original array's reference
  2. Second button overwrites the original data array reference with a new one using data = newArray

Update: Also, as Mark Rajcok, mentioned below you can use angular.copy to retain the original array's reference by emptying it out and adding new ones from the source like this:

fetchCards: function() {
      var d = $q.defer();
      $http.get("data/cards.php").success(function(data) {
                      angular.copy(data, cards);
                      d.resolve();
                }).error(function(data, status) {
                      d.reject(status);        
                 });
               return d.promise;
      },

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...