0

I am making an API call from my AngularJS app using the $http directive in a factory (I've tried both $http and $resource and I don't really care which I use as long as it returns the data), and I am getting either a $$state object when I don't use the .then() to unwrap the promise or an undefined.

This is the code for the factory:

app.service('dataService', ['$http', function($http) {
    return {
        quizQuestions: function() {
            return $http.get("http://localhost:59143/api/Questions")
                .then(function(response) {
                     console.log(response);
                     console.log(response.data);
                     console.log(response.data[0]);
                     return response;
                })
        }
    }
}])

When I call it from my controller, I do this:

app.controller('QuizController', ['$scope', '$http', 'dataService', function($scope, $http, dataService) {
    dataService.quizQuestions().then(function(data) {
        $scope.quizQuestions=data;
        console.log($scope.quizQuestions);
    })
}])

At this point, I'm not even trying to bind the data to the view and am just observing the console output. What I get with this configuration in the console is this:

{data: array(1), status: 200, heders: f, config: {...}, statusText: "OK"}
[{...}]
{Text: "...", *rest of object omitted for brevity but it is here*}
undefined

Can anyone tell me what I'm doing wrong?

As an aside, when I eliminate the factory all together and have the code in the controller as such:

app.controller('QuizController',['$scope', '$http', function($scope, $http) {
    $http.get("http://localhost:59143/api/Questions").then(function(response) {
        console.log(response);
        console.log(response.data);
        console.log(response.data[0]);
        $scope.quizQuestions=response.data;
        console.log($scope.quizQuestions);
        console.log($scope.quizQuestions[0]);
    })
}])

I get the console output of:

{data: array (etc)}
[{...}]
{text: (rest of obj)}
[{...}]
{text: (rest of obj)}

so it appears to be something in the factory?

I've looked at these other articles for some direction and the angular documentation but to no avail.

  • Not a duplicate, tried a .then() after the fact and that is when I got the problem. I could get the full http object if I just did something like: $scope.quizQuestions=dataService.quizQuestions(). It's only when I do the .then() that I get undefined. – Z. Campbell Mar 23 '18 at 19:12
  • Now your code seems to be OK. Try to create a [Minimal, Complete, and Verifiable example](http://stackoverflow.com/help/mcve) if possible in order to reproduce the error. – lealceldeiro Mar 23 '18 at 19:13

2 Answers2

0

In your service, you have already unwrapped the promise returned by $http.

So either do,

...
quizQuestions: function() {
  return $http.get("http://localhost:59143/api/Questions");
}
...

OR

Use .then() in your service but return a promise like this,

but don't forget to add $q as dependency,

quizQuestions: function() {
  let defer = $q.defer();
  $http.get("http://localhost:59143/api/Questions").then(function(response) {
  // ...
  defer.resolve(response); // or whatever you want to return
  }, function (error) {
    defer.reject(error);
  })
return defer.promise;
}

So basically in your service, you unwrapped the promise and then returned a static value.

Now in your controller, you are calling your service and trying to apply then() on a function who doesn't return promise.

Satish Kumar
  • 601
  • 6
  • 14
  • `$http` already returns a promise, using `$q` is an anti-pattern, [don't use them](http://www.codelord.net/2015/09/24/%24q-dot-defer-youre-doing-it-wrong/) – Aleksey Solovey Mar 23 '18 at 21:38
  • @AlekseySolovey You are right, that's why the first option, just return the response of $http. But if we have to process the response data and then return a promise, we have to use $q or Promise(). – Satish Kumar Mar 24 '18 at 22:54
  • BTW '...' in the second part meant the processing part. – Satish Kumar Mar 24 '18 at 23:04
0

The data is attached as a property of the response object:

app.controller('QuizController', ['$scope', '$http', 'dataService', function($scope, $http, dataService) {
    dataService.quizQuestions().then(function( ̶d̶a̶t̶a̶ response) {
        ̶$̶s̶c̶o̶p̶e̶.̶q̶u̶i̶z̶Q̶u̶e̶s̶t̶i̶o̶n̶s̶=̶d̶a̶t̶a̶;̶
        $scope.quizQuestions=response.data;
        console.log($scope.quizQuestions);
    })
}])

From the Docs:

$http Returns

A Promise that will be resolved (request success) or rejected (request failure) with a response object.

The response object has these properties:

  • data{string|Object} – The response body transformed with the transform functions.
  • status{number} – HTTP status code of the response.
  • headers{function([headerName])} – Header getter function.
  • config{Object} – The configuration object that was used to generate the request.
  • statusText{string} – HTTP status text of the response.
  • xhrStatus{string} – Status of the XMLHttpRequest (complete, error, timeout or abort).

-— AngularJS $http Service API Reference - Returns.

Community
  • 1
  • 1
georgeawg
  • 48,608
  • 13
  • 72
  • 95