76

I've got a simple controller that use $resource :

 var Regions = $resource('mocks/regions.json');

 $scope.regions = Regions.query();

I'm using this controller in a directive (in the link function)

var regions = scope.regions;

But regions is undefined. It's pretty logic the call is asynchronous.

My question is how can i do to wait the result and regions be an array with all data ?

UPDATE : 

Here the definition of the directive

app.directive('ngMap', function() {
  return {
    restrict: 'EA',
    replace: 'true',
    scope: {

    },
    template: '<div id="map"></div>',
    controller: 'AccordMapCtrl',
    link: function(scope, element, attrs) {
      var regions = scope.regions;
      console.log(regions);

      for (var region in regions) {}
    };
  });
Noopur Dabhi
  • 1,867
  • 25
  • 38
Thomas Pons
  • 7,709
  • 3
  • 37
  • 55
  • I had the same problem and used the solution by @AndreyPushkarev inside the link function. Basically all the logic in the link function is inside `$promise.then(function(result){...});`. – Elliot Vargas Feb 06 '14 at 15:16
  • Just to make sure I'm not misunderstanding - the "callback" approach to solving this problem technically works just as well as the "promises" approach, correct? (I prefer the syntax of promises, but it seems to me that callbacks would technically accomplish the same thing) – rinogo Aug 31 '16 at 21:27
  • Yes you get the choice $promise.then or a simple callback. The $promise approach is more "semantic" i guess – Thomas Pons Sep 01 '16 at 09:13

4 Answers4

186

If you want to use asynchronous method you need to use callback function by $promise, here is example:

var Regions = $resource('mocks/regions.json');

$scope.regions = Regions.query();
$scope.regions.$promise.then(function (result) {
    $scope.regions = result;
});
Andrey Pushkarev
  • 1,911
  • 1
  • 12
  • 8
  • 32
    Why make the two intermediate assignments? If, as I expect, `Regions` is not used elsewhere, then `resource('mocks/regions.json').query().$promise.then(function (result) { $scope.regions = result; });` would surely do the job. – Roamer-1888 Jun 22 '14 at 12:47
  • 18
    can be helpful to have intermediate assignments when debugging code – Josh Diehl Nov 10 '14 at 01:53
  • 2
    From $resource docs: ...invoking a $resource object method immediately returns an empty reference...This is a useful trick since usually the resource is assigned to a model which is then rendered by the view. Having an empty object results in no rendering, once the data arrives from the server then the object is populated with the data and the view automatically re-renders itself showing the new data. – jarz Mar 17 '15 at 12:35
  • OK, but does my version without intermediate assignments not behave in the same way? Nothing will be rendered until `$scope.regions = result` executes. – Roamer-1888 Mar 17 '15 at 12:53
  • 1
    @Roamer-1888 I agree with you that your code is functionally equivalent to the accepted answer in this simple exercise. I'm working on a more complex app, though, that returns data to the view from multiple tables. To keep my code cleaner and to implement the DRY principle, I have abstracted invoking the $resource object away into a reusable factory. I pass the unique portion of the path as a parameter from my controller to the factory, and return the data to my controller. Doing so requires me to have intermediate assignments similar to the accepted answer. – steveo Jun 29 '15 at 14:55
  • @steve, from what you say I would guess that intermediate assignment(s) are reasonable in your case. If you want a more considered opinion, you could always post in [Code Review](http://codereview.stackexchange.com). – Roamer-1888 Jun 29 '15 at 18:51
  • @SilvioTroia `result.status; // Will contain an object with HTTP status code and name. For example: {code: 200, name: "OK"}` – Andrey Pushkarev Nov 07 '15 at 06:12
36

If you're looking to get promise in resource call, you should use

Regions.query().$q.then(function(){ .... })

Update : the promise syntax is changed in current versions which reads

Regions.query().$promise.then(function(){ ..... })

Those who have downvoted don't know what it was and who first added this promise to resource object. I used this feature in late 2012 - yes 2012.

Mahbub
  • 3,108
  • 24
  • 29
  • It's available from 1.1.15. You might want to consider upgrading the version. – Mahbub Oct 21 '13 at 11:20
  • I'm using 1.2 RC for real app. And it's a mission critical app, I just didn't try some fancy stuff they added lately. That resource promise thing was used in our app last year in angular. We just added the patch some guy suggested and Angular Team marked "Good to Merge". It's not a big deal. If you care about that much then make a custom $http wrapper and use it like resource calls and you get promises. – Mahbub Oct 21 '13 at 11:28
  • I'm usign promise on resource in 1.0.8 it's just that the syntax is different :) – Thomas Pons Oct 21 '13 at 11:44
20

You could also do:

Regions.query({}, function(response) {
    $scope.regions = response;
    // Do stuff that depends on $scope.regions here
});
Andreas
  • 209
  • 2
  • 6
0
/*link*/
$q.when(scope.regions).then(function(result) {
    console.log(result);
});
var Regions = $resource('mocks/regions.json');
$scope.regions = Regions.query().$promise.then(function(response) {
    return response;
});
Nathan Tuggy
  • 2,237
  • 27
  • 30
  • 38
Ding
  • 1
  • 1