Mark Chidlow
Mark Chidlow

Reputation: 1472

Why do I have to use $promise with $resource?

Admittedly I am relatively new to Angular but I've come unstuck using ngResource for a REST call.

I followed a factory pattern which seems to be relatively common.

However my I only get access to the REST response by using a $promise.then. Which I understand you do not require with $resource.

So I have this factory...

var LookupsService = angular.module('LookupsService', ['ngResource']);

LookupsService.factory('Lookups', ['$resource',
  function ($resource) {
      return $resource('http://localhost:5001/api/lookups', {});
  }]);

And this fails (as undefined)

alert(Lookups.get().foo);

But this is fine

    Lookups.get()
        .$promise
        .then(function (lookups) {
            alert(lookups.foo);
        });

I'm obviously missing something here. Some kind of schoolboy error ;-)

UPDATE

Thanks for all your help - it is now very clear. I gave @fikkatra the tick for the clarity of her answer and snippet. But pretty much all the answers were helpful. I must be careful using Alert for debugging!

Upvotes: 3

Views: 4480

Answers (4)

fikkatra
fikkatra

Reputation: 5792

Using alert on a promise won't work, i.e. it won't show the results within the promise. However, angular has been designed to use the $resource service directly to bind to the scope. This means you can bind a $resource result to a scope object, and angular will take into account that the scope object is a promise when applying the binding. That's why alert(resourceResult) won't work, but $scope.myObj = resourceResult; (and then bind it in a view), will work.

Inserted code snippet to explain things more clearly:

var app = angular.module('myapp', ['ngResource']);

app.controller('myctrl', function($scope, $resource) {
  //this won't work:
  //alert("won't work: " + $resource('https://api.github.com/users/fikkatra').get());
  //but this will work
  $resource('https://api.github.com/users/fikkatra').get().$promise.then(function(user) {
    alert("will work: " + user.login);
  });
  //directly assigning $resource result to scope will work:
  $scope.user = $resource('https://api.github.com/users/fikkatra').get();
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular-resource.js"></script>
<div ng-app="myapp" ng-controller="myctrl">
  {{user.login}}
</div>

Upvotes: 3

shieldstroy
shieldstroy

Reputation: 1327

You actually don't have to use the $promise, it's just available if you want to.

Codepen: http://codepen.io/troylelandshields/pen/bpLoxE

angular.module('app', ['ngResource'])
.service('exampleSvc', function($resource){
  return $resource('http://jsonplaceholder.typicode.com/posts/1', {});
})
.controller('exampleCtrl', function(exampleSvc, $scope){
  $scope.result = exampleSvc.get(); 

  exampleSvc.get().$promise.then(function(val){
    //Do some other logic here on the val
    $scope.promiseResult = val;
  });

});

You can also assign the result of .get() to a variable on the scope and the result will be filled in when the request is resolved (in the first example above). This works well for assigning data to an object on your scope that will just end up being displayed on the page, but might not work well for other situations where you need to use the result of the .get() to do something else.

Upvotes: 1

Chris
Chris

Reputation: 27384

According to the specification you can pass in a success callback as outlined in this little code snippet.

var User = $resource('/user/:userId', {userId:'@id'});
var user = User.get({userId:123}, function() {
  user.abc = true;
  user.$save();
});

The success function callback will be called when the resource finishes.


Alternatively, you can use the promise syntax with get(), except you don't need to add your own promise as per your example. Instead you can simply do the following:

 Lookups.get()
        .then(function (lookups) {
            alert(lookups.foo);
        });

This is because get() returns a promise. When the promise is evaluated successfully then() will be called

Upvotes: 0

Katana24
Katana24

Reputation: 8959

You don't have to, and shouldn't need to, use $promise with $resource. The $resource service can be used like this:

(function() {
  'use strict';

  angular
    .module('app')
    .factory('MyService', MyService);

  MyService.$inject = ['$resource'];

  function MyService($resource) {
    return $resource('my/url/:id', {id: "@id"}, {
      'query': { isArray: false },
      'update': { method: "put" }
    });
  }
})();

It gives you back several HTTP methods that you can use in your code without you having to write them yourself. To use them you can do something like this:

function getActionTypes(){
      MyService.query(
        function success(result){
          // do stuff with result
        },
        function failure(result){
          console.error(result);
        });
    }

Upvotes: 2

Related Questions