0

I have a javascript function which for this question I have simplified. It actually does some things to the data retrieved from the $http call and then I want that data to be made available along with a promise to the function that called it:

getTopics = (queryString: string) => {
        var self = this;
        var defer = self.$q.defer();
        self.$http({
            // cache: true,
            url: self.ac.dataServer + '/api/Topic/GetMapData' + queryString,
            method: "GET"
        })
            .success((data) => {

                var output: ITopics = {
                    details: data
                }
                // output is correctly populated with data
                defer.resolve(output);

                // I also tried this and it get seen in the calling function either
                // defer.resolve('abc');
            })
        return defer.promise;
    };

This calls it:

return topicService.getTopics("/" + subjectService.subject.id)
       .then((data) => {
           // data seems to be not defined
           var x = data;
});

Can someone tell me what I might be doing wrong. I thought the resolve would return data also but it seems not to be doing so.

Bergi
  • 630,263
  • 148
  • 957
  • 1,375
  • Are you sure that `success` is being called? Try deleting `: void` too – Simon H Aug 13 '15 at 06:48
  • Yes it stops at var x = data in the debugger. But when I hover over data the chrome debugger does not show anything. –  Aug 13 '15 at 06:50
  • 1
    Looks like you are using typescript, but you are declaring your `data` result as `void` rather than e.g. `any`. I don't know for certain but void sounds like no real content – Simon H Aug 13 '15 at 06:52
  • I deleted : void and it is still the same. it goes to var x = data but data shows nothing. If I check the other point and look at output it is correctly populated with data –  Aug 13 '15 at 06:53
  • maybe because you forgot the closing tag of '{' in topicService. try adding '}' after the var x = data; – kdlcruz Aug 13 '15 at 06:56
  • @RGraham - yes it's populated there –  Aug 13 '15 at 07:05
  • @Anne Why the reference to `self`? Why are the `$q` and `$http` dependencies not resolved through injection? – CodingIntrigue Aug 13 '15 at 07:07
  • this is part of a much larger service. Just this part of the code is not working. $q and $http are injected into the service –  Aug 13 '15 at 07:08
  • @Anne I still can't see why you'd need `this` to reference services, but OK. Here is a minimal reproduction of the code you've posted. Assuming your AJAX code returns as you expect, the code works fine - http://jsfiddle.net/xnx24swp/ – CodingIntrigue Aug 13 '15 at 07:11
  • @Anne it seems to me that you are wrapping promises around promises for no particular reason. This is called the deffered-anti-pattern, I think you should remove the wrapping in $q and return the $httpPromise from $http service. – skubski Aug 13 '15 at 07:23
  • Avoid the [deferred antipattern](http://stackoverflow.com/q/23803743/1048572)! – Bergi Aug 13 '15 at 23:49

3 Answers3

2

Try this syntax, which is what I swtiched to when I moved some existing $q code to ES6

getTopics(queryString) {
    return this.$q((resolve, reject) => {
        this.$http.get(self.ac.dataServer + '/api/Topic/GetMapData' + queryString)
        .success((data) => {
            resolve({details: data});
        })
        .error( (err) => reject(err) );
    });
}

or much better, as suggested by Bergi:

getTopics(queryString) {
    return this.$http.get(self.ac.dataServer + '/api/Topic/GetMapData' + queryString)
        .then( data => ({details: data}) );
    });
}

$http.get().then(...) is itself a promise that can be further used by the calling code.

Bergi
  • 630,263
  • 148
  • 957
  • 1,375
Simon H
  • 20,332
  • 14
  • 71
  • 128
  • Avoid the [promise construction antipattern](http://stackoverflow.com/q/23803743/1048572)! – Bergi Aug 13 '15 at 23:49
  • Ha! Thanks for the tip - I've changed in my own code but am not sure exactly how Anne should now change hers – Simon H Aug 14 '15 at 16:11
  • In this case, it's just `getTopics(…) { return $http.get(…).then(data => ({details:data})); }`. Can you help us improving the answers to the linked question? What parts of them are hard to understand? – Bergi Aug 16 '15 at 18:20
  • Thanks - hopefully I have interpreted you correctly – Simon H Aug 16 '15 at 18:42
  • Those parens around the object literal are very important in arrow functions :-) – Bergi Aug 16 '15 at 19:03
2

Perhaps it's a matter of personal preference, but I use the $q.defer() technique to "promisify" a synchronous function. In case of something that's already asynchronous, i.e, already a promise, like $http and $timeout, I set a success handler using the then function, modify the result as necessary and return the object as a promise using $q.when()

Refer to the when function in the $q documentation

I've created a Plnkr (in Javascript) that demonstrates the use of $q.when in this situation. Relevant code:

$scope.results = ['a', 'b', 'c', 'd'];
$scope.getTopics = function() {

  //Replace $timeout with $http
  // $http({
  // }).then....

  return $timeout(function() {
      console.log('Simulating HTTP response');
      return $scope.results;
    }, 1500)
    .then(function(res) {
      var updatedRes = [];
      //Modify the HTTP/timeout results
      console.log('Modifying HTTP/timeout result');
      angular.forEach(res, function(item) {
        item = item + '1';
        updatedRes.push(item);
      });

      //Wrap the result object in $q.when to create a promise
      return $q.when(updatedRes);
    });
};

$scope.getTopics().then(function(data) {
  console.log('Using the modified result');
  $scope.updatedResults = data;
  console.log('getTopics result = ', data);
});
WeNeigh
  • 3,489
  • 3
  • 27
  • 40
0

Try this one.

return topicService.getTopics("/" + subjectService.subject.id)
   .then((data): void => {
       // data seems to be not defined
       var x = data;
   } // ADDED
);

I think it's because of the missing } in the code that's why data doesn't have any value in the getTopics function.

kdlcruz
  • 1,368
  • 13
  • 20
  • I'm sorry this was just a mistake when I was entering the question. The } is actually there in my code. –  Aug 13 '15 at 07:03