2

I am trying to get the response from factory to controller. but when i am calling a function of factory from controller, then the controller not waiting for its response. and giving "undefined".

here it is my controller.js

app.controller('customerCommentsController',function($scope,$http,$stateParams,$sce,$timeout,Comments){     

var commentsdata = '';

Comments.init(1,5);

$scope.total_comments = Comments.total();
console.log($scope.total_comments); //undefined 

$scope.positive_comments = Comments.positive();
console.log($scope.positive_comments);  //undefined 

$scope.commentsdata = Comments.getcomments(1,30);       
console.log($scope.commentsdata);   //undefined     
});

here I am calling init() method which gets the response from ajax, which takes some time to execute , but before it could complete, the other 2 statement (total() and positive() method) execute below the init method. and that not gets initialize because of init method not completed. and that why I am getting undefined. and same problem is coming when I am calling getcomments method which doesn't wait for its response.

here it is my factory

app.factory("Comments",function($http,$timeout,$q){

var commentshtml = [];
var commentshtml1 = [];

return {
    init :  function(start,end) {  
    var request = $http({   
            method:"post",
            url:"/comments.php",
            data: {start:start,end:end},                
            headers: {'Content-Type' : 'application/x-www-form-urlencoded'}                     
        });     

    request.success(function(data){                 
            commentshtml = data;            
        });             
    },      
    total : function() {

                return commentshtml.total_comment;                    
    },
    positive : function(){

            return commentshtml.per_positive_comment;               
    },
    getcomments : function(start,end) { 

        var promise  = $http({  
            method:"post",
            url:"/comments.php",
            data: {start:start,end:end},                
            headers: {'Content-Type' : 'application/x-www-form-urlencoded'}                     
        });

        promise.success(function(data){                 
            commentshtml1 = data.comments;
            console.log(commentshtml1); //giving the object             
            return commentshtml1;   
        }); 

    }
};
1
  • you should use a deferred object (see Ignat's answer below) or at least callback. Commented Sep 1, 2015 at 8:33

4 Answers 4

2

it's better to use $q module to work with asynchronous functions in angular. Read this docs:

$q documentation

Sign up to request clarification or add additional context in comments.

Comments

1

Do this way:

In factory

   return {
    init :  function(start,end) {  
     return $http({     //return the promise 
            method:"post",
            url:"/comments.php",
            data: {start:start,end:end},                
            headers: {'Content-Type' : 'application/x-www-form-urlencoded'}                     
        });     
    }
  getcomments : function(start,end) { 
             return $http({   //return the promise
            method:"post",
            url:"/comments.php",
            data: {start:start,end:end},                
            headers: {'Content-Type' : 'application/x-www-form-urlencoded'}                     
        });

}

In Controller

Comments.init(1,5).then(function(){
 $scope.total_comments = Comments.total();
console.log($scope.total_comments);  

  $scope.positive_comments = Comments.positive();
console.log($scope.positive_comments);
 });
Comments.getcomments(1,30).then(function(data){
  $scope.commentsdata =data.comments;

})

Or the best way use resolve property in ng-route or ui-router

1 Comment

:- Thanks for your help. It worked for me. thanks a lot :)
1

You are performing asynchronous request, the problem is that you retrieve data before she is defined.

A good practice is to use promise. You hace to know that the $http service return promises, and has some callback method, like .success() and .then() for example.

For promise, angular provide us a pretty good tool : $q.defer().

$q.defer() is a promise manager from the deferred API.

$q.defer() get 2 methods :

  • resolve(value) : which resolve our associated promise, by giving her the final value

  • reject(reason) : which resolve an promise error.

So you can do the following :

Controller

(function(){

function Controller($scope, Comments) {

  //Retrieve our init promise
  var promise_init = Comments.init();

  //Retrieve our total promise
  var promise_total = Comments.total();

  promise_init.then(function(){
    //Return promise for chaining
    return promise_total;
  }).then(function(total){
    //Retrieve total of comments
    $scope.total = total;
  }).catch(function(err){
    //Catch error of total comments
    $scope.total = err;
  });

}

angular
.module('app', [])
.controller('ctrl', Controller);

})();

Service

(function(){

  function Service($q){

    var commentshtml = [];

    function init(){
      //Create defer object
      var defer = $q.defer();
      commentshtml = ['a', 'b', 'c'];
      //Simulate latency
      setTimeout(function(){
        //Resolve our promise
        defer.resolve();
      }, 2000);

      //Return a promise
      return defer.promise;
    }

    function total(){
      var defer = $q.defer();
      commentshtml.length < 3
      ? defer.reject('error length')
      : defer.resolve(commentshtml.length);
      return defer.promise;
    }


    return {
      init: init,
      total: total
    };

  }

  angular
    .module('app')
    .factory('Comments', Service);

})();

HTML

  <body ng-app='app' ng-controller='ctrl'>

    <h2>Total : {{total}}</h2>

  </body>

You can see the Working Plunker

Comments

0

Write your all $scope variable in then function.

So your Controller.js :

app.controller('customerCommentsController',function($scope,$http,$stateParams,$sce,$timeout,Comments){     

    var commentsdata = '';

    Comments.init(1,5).then(function(){

         $scope.total_comments = Comments.total();
         console.log($scope.total_comments); //undefined 

         $scope.positive_comments = Comments.positive();
         console.log($scope.positive_comments);  //undefined 

         $scope.commentsdata = Comments.getcomments(1,30);       
         console.log($scope.commentsdata);   //undefined     
    }
});

You have to return your $http request.

So your init function look like :

init : function(start,end) {  
return $http({   
        method:"post",
        url:"/comments.php",
        data: {start:start,end:end},                
        headers: {'Content-Type' : 'application/x-www-form-urlencoded'}                     
    }).success(function(data){
          return commentshtml = data;
    });
}

And your Factory :

app.factory("Comments",function($http,$timeout,$q){

var commentshtml = [];
var commentshtml1 = [];

return {
init :  function(start,end) {  
return $http({   
        method:"post",
        url:"/comments.php",
        data: {start:start,end:end},                
        headers: {'Content-Type' : 'application/x-www-form-urlencoded'}                     
    }).success(function(data){
          return commentshtml = data;
    });
},      
total : function() {

            return commentshtml.total_comment;                    
},
positive : function(){

        return commentshtml.per_positive_comment;               
},
getcomments : function(start,end) { 

    var promise  = $http({  
        method:"post",
        url:"/comments.php",
        data: {start:start,end:end},                
        headers: {'Content-Type' : 'application/x-www-form-urlencoded'}                     
    });

    promise.success(function(data){                 
        commentshtml1 = data.comments;
        console.log(commentshtml1); //giving the object             
        return commentshtml1;   
    }); 

2 Comments

bhaskar:- If I use then function , then I am getting error "TypeError: Cannot read property 'then' of undefined".
Yes because you didn't return factory init function's $http.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.