0

I'm trying to use Angular promise API in my app. And I was a little confused. I created a factory like in code below

factory('transport', function ($resource) {
    var baseUrl = "http://aw353/WebServer/odata/Payments";
    return $resource("", {},
        {
            'getAll': { method: "GET",params: {svcUrl:"@svcUrl"}, url: baseUrl + ":svcUrl" },
            'save': { method: "POST", params: {svcUrl:"@svcUrl"}, url: baseUrl+ "(:svcUrl)" },
            'update': { method: 'PUT', params: {svcUrl:"@svcUrl", key: "@key" }, url: baseUrl+ "(:svcUrl)" + "(:key)"},
            'query': { method: 'GET', params: {svcUrl:"@svcUrl", key: "@key" }, url: baseUrl +"(:svcUrl)" + "(:key)"},
            'remove': { method: 'DELETE',  params: {svcUrl:"@svcUrl", key: "@key" }, url: baseUrl + "(:svcUrl)" + "(:key)"}
        });
});

I'm using this factory in controller and when I implement the function like this

var getData = function () {
    (transport()).$getAll({svcUrl:"//BasicSettings"})
        .then(function (data) {
            $scope.DataSource = data.value[0];
            console.log($scope.DataSource.SystemName);
        });
}();

it fails and I get error "Cannot read property '$getAll' of undefined"
But when I use 'new' keyword like this

var getData = function () {
    (new transport()).$getAll({svcUrl:"//BasicSettings"})
        .then(function (data) {
            $scope.DataSource = data.value[0];
            console.log($scope.DataSource.SystemName);
        });
}();

it works.

I know the difference between constructor function and usual function. But I don't understand why promise API works only in second case.
Can anyone help me to understand how it works?

Marc Kline
  • 9,399
  • 1
  • 33
  • 36
alinaish
  • 456
  • 2
  • 7
  • 18
  • Have you tried a `console.log(transport()); console.log(new transport());`? Looks like `transport` is just a constructor that might not be called as a function. – Bergi May 22 '14 at 15:14
  • It's not "the promise api" that works or not, it's simply the object creation that fails (or not). And accessing a property (method) on a non-object (`undefined`) is doomed to fail then, regardless of what its expected value is. – Bergi May 22 '14 at 15:15
  • Can you provide a plnkr demo of your issue? (would be helpful to see more surrounding code) – s_hewitt May 22 '14 at 16:18

1 Answers1

2

Try

transport.getAll(...).$promise.then(...)

instead.

I know the difference between constructor function and usual function. But I don't understand why promise API works only in second case.

well because the API is designed that way.You have instance methods and class methods.

To create an instance you need the new operator and then you get access to instance methods.

The $resoure() method is a factory to extend "$resource" and returns a constructor function ,that has class methods,and instances of the that constructor function have instance methods.

function Resource(value) {
    shallowClearAndCopy(value || {}, this);
}

forEach(actions, function (action, name) {
    var hasBody = /^(POST|PUT|PATCH)$/i.test(action.method);

    Resource[name] = function (a1, a2, a3, a4) {
        var params = {}, data, success, error;
(...)

A simple click on view source in the doc shows that class methods are created ADHOC on Resource constructor

https://github.com/angular/angular.js/blob/master/src/ngResource/resource.js#L492

Marc Kline
  • 9,399
  • 1
  • 33
  • 36
mpm
  • 20,148
  • 7
  • 50
  • 55
  • OP has a working solution already. He only wants to understand the difference, not get a third (probably non-working) variant. – Bergi May 22 '14 at 15:15
  • reading angular source code is very interesting because they dont hesitate to write hyper dynamic,prototype less code.Authors are not really concerned by optimization,their first concern is writing monadic apis,$resource is a functor. – mpm May 22 '14 at 15:35
  • Your alternative may be better described as `transport.getAll(...).$promise.then(...)` – Marc Kline May 22 '14 at 15:39
  • Oh, that's interesting. But you don't instantiate an object and call the methods on the `transport` class itself, wouldn't they miss some initialisation? – Bergi May 22 '14 at 17:35
  • not if the initialisation is done inside constructor.getAll. constructor.getAll !== instance.getAll – mpm May 22 '14 at 17:40
  • +1 for ""$resource" and returns a constructor function" This is why `new transport()` works and `transport()` does not. See: http://jsfiddle.net/8Pd4g/4/ – s_hewitt May 22 '14 at 18:22