0

About 1 in every 10 times I refresh my project, the data from my database is not retrieved and I have to refresh the page again to get it. I tried adding a 101ms timeout onto the function which retrieves the data, and this worked- but also removed a lot of other functionality of the site.

The problem is that sometimes the page loads before the data is retrieved.

Is there a better way to solve this than using a timeout? My code for the POST is below:

 get_data: function (kpi, date_from, date_to, callback) {
        var config = {
            method: 'POST',
            url: '/getData',
            data: {
                kpi: kpi,
                date_from: date_from,
                date_to: date_to
            }
        };
        $http(config)
            .success(function (data) {
                callback(data);
            })
            .error(function (data, status, headers, config) {
                console.log(data, status, headers, config);
            });
    }

And then where this method is called (currently with the timeout, which is breaking other site functionality):

  $scope.update_all_data = $timeout(function(){
    $scope.show_loading = true;
    var date_from = findDateUnix($scope.myDateFrom, $scope.availableDates);
    var date_to = findDateUnix($scope.myDateTo, $scope.availableDates);
    UpdateSvc.get_data($scope.kpi_selected, date_from, date_to, function(res){
        raw_data = [];
        if(res.raw_data != null) {
            if(res.raw_data.length > 0){
                raw_data = res.raw_data;
                skey_data = [];
                if(res.skey_data != null) {
                    skey_data = res.skey_data;
                }
                var num = $scope.show_tab.indexOf(true);

                $scope.filtering = generateCategories();
                $timeout(function(){
                    $scope.display_nodata = false;
                    resizeObjects();
                    $('.md-datepicker-input').prop('disabled', true);

                    //Take out loading
                    $scope.show_loading = false;
                }, 100);
            }else{
                $scope.display_nodata = true;
                $timeout(function(){ $scope.show_loading = false;}, 100);
            }

        }else{               
            $scope.display_nodata = true;
            $timeout(function(){ $scope.show_loading = false;}, 100);
        }
    });
}, 101);
  • to use `res` from `UpdateSvc.get_data()` you need to return it. Currently you are calling a callback that doesn't return it. Change it to `return $http(config)...` and `return callback(data);`. What you will return will be a Promise that you need to resolve – Aleksey Solovey May 29 '18 at 15:14
  • I'm not sure what you mean. Change what to return $http(config)... and return callback(data); ? The function isn't returning anything – Oliver James May 29 '18 at 15:18
  • Ahem ... use [promises](http://andyshora.com/promises-angularjs-explained-as-cartoon.html) – Protozoid May 29 '18 at 15:38

1 Answers1

0

The problem is that sometimes the page loads before the data is retrieved.

I'm not sure what you mean by this. In an AngularJS application, the entire page must be loaded before AngularJS even begins to work. So your data (retreived with $http) will ALWAYS be loaded after the page loads, unless it is injected server-side.

I don't think you are having any issues retrieving the data from $http. You can easily confirm this by eliminating or commenting out all the code that does not deal directly with data retrieval. I would also strongly recommend the following changes:

First, using callbacks with $http is an antipattern: Why are Callbacks from Promise `.then` Methods an Anti-Pattern

(Note: newer versions of AngularJS use then/catch instead of success/error)

You should, instead use the built-in promise system. Calls to $http return a promise object that can be used directly like so:

 get_data: function (kpi, date_from, date_to) {
   var config = {
     method: 'POST',
     url: '/getData',
     data: {
       kpi: kpi,
       date_from: date_from,
       date_to: date_to
     }
   };
   // return the $http call
   return $http(config)
     .error(function (data, status, headers, config) {
       console.log(data, status, headers, config);
     });
 }

There is not really any reason to call $timeout in update_all_data function. You are adding 101 seconds AFTER your $http call has already returned. All that does is delay the display of the data further. Here, we are also calling the success function on the promise returned from the $http call in the service:

  $scope.update_all_data = function(){
    var date_from = findDateUnix($scope.myDateFrom, $scope.availableDates);
    var date_to = findDateUnix($scope.myDateTo, $scope.availableDates);
    UpdateSvc.get_data($scope.kpi_selected, date_from, date_to).success(function(data) {
      console.log(data);
    });
  });

If this works and your data is logged 10/10 times then the issue is not with data retreival, it is with the rest of the code in your update_all_data function.

Pop-A-Stash
  • 6,572
  • 5
  • 28
  • 54
  • Thanks for this. I am currently looking more into promises. The code you provided just gave me a constant 'loading' page with no compiler errors and no data on the console. I think the issue is the displaying the data before the $http call returns, as the timeout fixes this issue completely. So the page is displaying before the relevant data is retrieved. I've console logged the data and on the 1 in 10 times the data doesn't load, the data object is empty. The other 9 times it is not empty – Oliver James May 30 '18 at 09:21