leonsPAPA
leonsPAPA

Reputation: 797

AngularJS factory returns 'undefined'

when I define the factory method like this

dataFactory.all = function() {
  return 'test01';
}

and call it in controller like this

console.log(Data.all());

I can get test01 printed. However, when I add some logic in factory all() method like this

  dataFactory.all = function() {

    $http
      .get('/api/hey')
      .success(function(data) {

        $http
          .get('/api/hi')
          .success(function(data) {

            return 'test'; // 'test' can not be printed, and console show 'undefined'
          });
      });
     //return 'test01'; //can be printed;
  };

then the 'test' can not be printed via the controller. Because I put the return statement in the callback?

Please let me know what I am doing wrong?

Thanks.

Upvotes: 0

Views: 1230

Answers (5)

paul trone
paul trone

Reputation: 702

Take a look at angular's $q (docs). With $q you can create a deferred object and return it's promise from your factory method.

That should allow you to retrieve the resulting data from your $http call in a then callback since your factory will be returning a promise:

dataFactory.all = function() {
  // create deferred object
  var deferred = $q.defer();

  $http.get('/api/hey')
  .success(function(data) {

    $http.get('/api/hi') 
    .success(function(data) {

      // resolve the promise with your http request result, this value will 
      // be the result passed to  your factory method's 
      // `then` callback
      deferred.resolve(data);
    }
  }

  return deferred.promise;
}

update

@HankScorpio is right, this could be simplified greatly by returning the $http.get function calls because they return promises themselves:

dataFactory.all = function() {
  return $http.get('/api/hey').success(function(response) {
    return $http.get('/api/hi');
  });
}

Working update is here: http://plnkr.co/edit/wtMnOjjUnKV5x8CQrbIm?p=preview

Upvotes: 1

manzapanza
manzapanza

Reputation: 6205

Because you are not returning any value in the scope of the all method and also you need to pay attention that $http return a promise.

So.. your method could be somemething like this:

dataFactory.all = function(jobname) {
  return $http.get('/api/jobs/' + jobname + '/realtimeData').success(function(realtime) {
    return $http.get('/api/jobs/' + jobname + '/nonliveData').success(function(nonlive) {
      return 'test';
    });
  });
};

Or.. to void nested promises you could refactor a bit your code using Flattened Promise Chains :

dataFactory.all = function(jobname) {
  return $http.get('/api/jobs/' + jobname + '/realtimeData').then(function(realtime) {
    // do something with realtime
    return $http.get('/api/jobs/' + jobname + '/nonliveData');
  }).then(function(nonlive){
    return 'test';
  });
};

And because your method all now return a promise, you need to:

dataFactory.all(jobname).then(function(nonlive){
  console.log(nonlive); // should return test!
});

Upvotes: 1

Matthew Merryfull
Matthew Merryfull

Reputation: 1496

I don't think its because you've built it incorrectly, but it looks as though your factory ($http) method is running asynchronously. Try returning a promise like so:

datafactory.all = function() {

   return new Promise(resolve, reject){
       // Your logic here...

     $http
        .get('/api/hey')
        .success(function(data) {
            resolve(data);
        })
        .fail(function(err){
           reject(err);
        });
     }

};

Then you can consume your factory method like so:

datafactory.all().then(function(result){
   // Success!
}, function(err){
   // Error!
});

Upvotes: 1

HankScorpio
HankScorpio

Reputation: 3651

Yes, exactly as you pointed out, you put the return in the callback function. the all() function has no return statement, and by default all functions will return undefined.

The issue you're encountering is that you're now dealing with an asynchronous function that will return data at an unknown time in the future (as opposed to synchronous functions, which return data immediately to be available to the next line of code).

In this case, you're using $http methods, and $http.get() will return a promise. https://docs.angularjs.org/api/ng/service/$q

Check out the examples on the $http documentation. Specifically, look at what they do with the then() functions: https://docs.angularjs.org/api/ng/service/$http

Upvotes: 1

atfornes
atfornes

Reputation: 468

you are doing some asynchronous calls in your code, please visit this question to get more details and information How do I return the response from an asynchronous call?

Upvotes: 1

Related Questions