0

Angular noob here. I'm building an app that needs to poll a url every second, and store that data persistently, as it needs to be accessed by multiple views/controllers.

What I've done to handle this is put my http request into a factory, and the data is made available to controllers through functions in the factory. The issue I'm having now is that the factory function is envoked before the http request, causing errors in my app.

Here is the code:

App.factory('metrics', function($http){
    var service;
    var users = [{laps:[]}];
    var updateMetrics = function(){
        //updates the users array in the factory
    };
    $http.get('data.csv').success(function(data) {
        var temp_array = data.split(" ");
        updateMetrics(0, temp_array);
    });

    service.lastLapInfo = function(){
        var lastlap = [];
        for (var i=0; i<users.length;i++)
        {
            var lap = users[i].laps[users[i].laps.length-1];
            lastlap.push(lap);
        }
        return lastlap;
    };
    return service;
});

App.controller('mainController', function($scope, $http, metrics) {
    $scope.users=metrics.lastLapInfo();
});

lastLapInfo() is getting called before the http request which is causing errors as there is no data in the array. Any thoughts?

Additionally - if I'm generally going about the wrong way to meet my use case (e.g. I should be using something else instead of a Factory) let me know!

1
  • do that stuff in the success callback, when you actually have the data. Commented Oct 10, 2014 at 22:04

2 Answers 2

2

This is a typical use case of a promise, or the angular's $q service.

The following approach, uses a factory that returns a promise:

App.factory('metrics', function($http){
   var service;
   ...
   service.load = function () {
      return $http.get('data.csv');
   });
   return service;
});       

In the controller you then call your metrics service, and you make use of the promise:

App.controller('mainController', function($scope, $http, metrics) {
    metrics.load().then(function(response) {
       // at this point you know for sure that the request has terminated
       // you can call the service again to run lastLapInfo or do the logic in here.
    });
});
Sign up to request clarification or add additional context in comments.

2 Comments

Very cool! Extending this how would I go about setting that http request to poll every second? Only think I can think off, is to have another function e.g update() in the factory, and call that function at a particular interval from each one of my controllers using the factory. Is there a better way?
you can use $interval service to repetitively load the load method in your service. This is further explained here: stackoverflow.com/questions/14944936/… with an example here plnkr.co/edit/iMmhXTYweN4IrRrrpvMq?p=preview.
1

If you don't have the data immediately, either deal with that by indicating it in the return value (null, undefined, []), or return a promise instead, which you'd also store and resolve later after fetching the data initially.

So something like

var deferred = null;

$http.get(...).then ({
  if (deferred) {
    deferred.resolve(result);
    deferred = null;
  }
});

service.lastLapInfo = function(){
  if (no metrics) {
    deferred = $q.defer()
    return deferred;
  }
  else {
    return metrics;
  }
};

should work, depending on how you want to structure it.

Edit: linked $q from comment.

1 Comment

Yes. I recommend OP to look at AngularJS $q docs.angularjs.org/api/ng/service/$q

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.