Mike Sav
Mike Sav

Reputation: 15291

AngularJS view doesn't wait for $http.get

In my controller I have the following...

$scope.products = dataService.getJsonData();
console.log($scope.products);

and in my dataservice I have the following

.service('dataService', function ($http) {

        this.getJsonData = function () {
            return $http.get('path/to/json/products.json').then(function (response) {

                // don't send back everything....
                var productData = response.data;
                console.log(productData);
                return productData;

            });

        };

and in my view I have the following...

<div ng-repeat="product in products">

    Name: {{ product.name }} <br>
    Price: {{ product.price }}
    <hr>
</div>

in my rendered view the repeat is showing only 3 items (products is an array of 15 objects). When looking at the console the repeat in the view or products is made of Object { then=function(), catch=function(), finally=function()} but the log from the dataservice is out putting the desired object array. I don't understand why the output isn't waiting for the returned data, I thought this was asynchronous? How can I make the view wait for the dataservice without using a $timeout. Has anyone else had this problem? Thanks in advance.

UPDATE *

From a bit of googling I'm pretty sure I need to add a resolve to my $routeProvider, the $routeProvider currently looks like so:

.when('/', {
      templateUrl: 'views/main.html',
      controller: 'MainCtrl',
      resolve:{
        // i need to put something here...
      }
  })

Upvotes: 2

Views: 4011

Answers (4)

Lajos Veres
Lajos Veres

Reputation: 13725

With $resource it is a bit easier, like this:

dataService.factory('getJsonData', ['$resource',
  function($resource) {
    return $resource('path/to/json/products.json');
  }
]);

The other parts are the same.

Upvotes: 1

bluehallu
bluehallu

Reputation: 10285

The actual update is happening in a callback, so you need to wrap it in $apply. Because it's happening in a service, you must use $rootscope

.service('dataService', function ($http,$rootScope) {

    this.getJsonData = function () {

        return $http.get('path/to/json/products.json').then(function (response) {
            $rootScope.$apply(function () {
                // don't send back everything....
                var productData = response.data;
                console.log(productData);
                return productData;

            })
        });     
    };

From the angular promises docs

// since this fn executes async in a future turn of the event loop, we need to wrap our code into an $apply call so that the model changes are properly observed.

Edit: As OdeToCode pointed out, this is really not needed. The reason is that what http.get returns is an Angular promise, which is already doing an $apply internally on the .then() callbacks.

Upvotes: 0

MentalRay
MentalRay

Reputation: 344

hmm not sure if it will help, because angular is async but try adding this to your controller before using the data.

dataService.getJsonData().success(function (response){
  $scope.products = response
})

Upvotes: 2

Reite
Reite

Reputation: 1667

When you call dataService.getJsonData() it doesnt return the data that the $http.get returns, it returns a promise that will be fulfilled with the data in the future. I would recommend you to read up on promises. You can read about the angular implementation here.

As I mentioned, the function returns a promise that will be fulfilled, so you need to set the data in the scope when the promise is fulfilled. Change your controller to this:

dataService.getJsonData().then(function (products) {
    $scope.products = products
})

Upvotes: 5

Related Questions