AngularJS - how to handle long running requests for data needed in controller/services

When my angular app first loads, I need to make a couple requests for some fairly large data. This data is then used in controllers and services to determine how to display the page. I'm getting all sorts of JavaScript errors because the controllers and services are trying to access this data before the request has returned.

I know in the HTML pages, you can bind to this asynchronous data, and angular will populate it for you when the request returns. However, I have some pretty complex logic happening in my controllers and services based on this data. So, I guess I have 2 questions.

  1. Is there anyway to somehow work with asynchronous data in the controllers and services?
  2. Is there a way to prevent angular from trying to render the page until after the data has returned? This basically makes the data requests synchronous, and I am ok with that. This would only be on the initial full HTML page load.

My attempt at a jsFiddle showing this can be found here: http://jsfiddle.net/sES9T/

The basic flow should be like this: Inside your controller function, make the $http request, and in the success() callback, set your $scope variables as needed. Is your flow different from that?

Also, use the ng-show directive to hide your DOM elements until the scope has the data you need.

Your controller will look something like this:

MyCtrl = ( $scope, $http ) ->
  promise = $http.get "/url"
  promise.success ( data ) ->
    $scope.foo = data

And your view will look like this:

div(ng-show="foo")
  p Here is my data, and some other stuff
  p {{ foo }}

EDIT

I've modified your jsfiddle here:

http://jsfiddle.net/sES9T/4/

It works as expected, the problem was that you were trying to access properties on undefined variables, which was throwing an error. Also, on the third test, the variable was named wrong, but still needs to be checked when named right.

I'd recommend coffeescript, since those if statements can be made a lot more terse with the existential (?) operator, like so:

myLargeData?.data

That code will check if myLargeData is defined and non-null before trying to access it's properties, like I had done manually above. If it IS undefined or null, it will return undefined, instead of causing an error.

I would suggest you to use router's resolve in order to load and process all required data. The controller will be executed only when all resolves are actually resolved. So the view will not be rendered at all, until your requests are completed and data is processed. I do believe this is a more elegant and recommended approach.

Also, you should extract all your data loading and processing logic into a separate service and relay the work to your service from the resolve. Your service should return a promise object that will be resolved when all processing is complete.

Please see the documentation for $routeProvider (the "resolve" property).