0

here is a piece of code I am struggling with - I have a controller (zmApp.MonitorCtrl) that is calling a factory (ZMFactory) with an HTTP request.

The problem I am facing is this: a) When the controller calls ZMFactory.getMonitors() it returns undef and I get an error ERROR: Error: undefined is not an object (evaluating 'ZMFactory.getMonitors().then')

b) After this error comes up, the http request in the factory is processed

I am a little confused. Can you please check if the factory has been set up correctly to return a promise?

var app = angular.module('zmApp.controllers');

app.controller('zmApp.MonitorCtrl',  function($ionicPlatform, $scope,$http,ZMFactory)
{
            
            $scope.monitors=[];
            console.log("***CALLING FACTORY");
            ZMFactory.getMonitors().then(function(data)
            {
               $scope.monitors = data;
               console.log ("I GOT " +$scope.monitors);
            });
               
});



app.factory('ZMFactory',['$http', '$rootScope',function($http,$rootScope)
{
    //var factory = {};
    var monitors =[];
    return {
        getMonitors: function()
        {
            console.log("***MAKING REQUEST");
            $http({
                    url:'http://myurl.com:9999/zm/index.php?skin=xml',
                    method:'post',
                    headers: {'Content-Type': 'application/x-www-form-urlencoded',
                               'Accept': '*/*',
                               },
                        transformRequest: function(obj) {
                               var str = [];
                               for(var p in obj)
                               str.push(encodeURIComponent(p) + "=" + encodeURIComponent(obj[p]));
                               var foo= str.join("&");
                               console.log ("****RETURNING "+foo);
                               return foo;
                        },
                        transformResponse: function(data)
                        {
                            var x2js = new X2JS();
                            var json = x2js.xml_str2json(data);
                            console.log ("***Transmogrifying XML to JSON");
                            return json;
                        },
                        data: {username:'xxx',
                               password:'xxxx',
                               action:'login',
                               view:'console'}
                               
                      }) //http
                      .success (function(data)
                      {
                          console.log("****YAY"+JSON.stringify(data));
                                   
                          var subobj =data.ZM_XML.MONITOR_LIST.MONITOR;
                          var len = subobj.length;
                          for (var i =0; i< len; i++)
                          {
                           console.log ("HERE " + subobj[i].NAME);
                           monitors.push(subobj[i]);
                           }
                          // $rootScope.$broadcast ('handleZoneMinderMonitorsUpdate',monitors);
                           return monitors;
                        }) //success
                        .error(function(data, status, headers, config)
                        {
                           console.log("***OOPS "+status + " H: "+data);
                           return monitors;
                        });

        } //getMonitors
    };//return
    console.log ("**** NEVER *****");
                        
}]);

6
  • do you need a dependencies array for the controller? Commented Apr 6, 2015 at 23:36
  • Hi Plato, I am not sure, but I don't think so -- the factory is callable from the controller. Commented Apr 6, 2015 at 23:51
  • ah, i see, yes the getModules function is not returning a promise. sorry i don't know how to construct a promise. Commented Apr 6, 2015 at 23:59
  • one way to do it would be to move the success/error handlers out of the getMonitors function; and return $http({ ...}); then you could handle .then(onSuccess, onError) in the controller. but it is probably better to research and create your own promise wrapping the entire http req/rep Commented Apr 7, 2015 at 0:00
  • 1
    docs.angularjs.org/api/ng/service/$q#! Commented Apr 7, 2015 at 0:07

2 Answers 2

1

The key to the answer is in the wording of your own question:

Can you please check if the factory has been set up correctly to return a promise

You need to return it. Right now your getMonitors function (if I remove all the code irrelevant to the question) is as follows:

getMonitors: function(){
  $http({})
    .success(function(data){
       // convert data to monitors
       return monitors;
    });
}

This is a function call that doesn't return anything, or rather, returns undefined. There is no "magic" with promises - it's just as any other object - you need to return it to the caller.

So, two things you need to do:

1) Change from .success to .then. .then generates a new chained promise that delivers, when returned, the monitors to the consumer (that you are returning in the .then handler). On the other hand, .success returns the original promise (generated by $http) and data returning from .success is lost.

2) Actually return the $http call (or, rather, $http().then() call)

Here's conceptually how this would look like:

app.factory('ZMService', function ZMServiceFactory($http){
    return {
        // getMonitors function of the ZMService service
        getMonitors: function(){
          return $http({})
            .then(function(response){
               var data = response.data;
               // convert data to monitors
               return monitors;
            });
        }
    };
});

(also, noticed how I renamed your service from ZMFactory to ZMService. A "factory" in the name is a misnomer. The factory is the function that generates the instance - hence "the factory" - but the instance itself is an object, which is called a "service" in Angular)

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

8 Comments

thanks. My original code above did have a return right above getMonitors in the factory. Is that not equivalent? Also in your code, can you please see if there should be a { after return? I'm trying your suggestion and am getting other issues which I'll outline, once I hear back on this clarification
@user1361529, I think the return that you are referring to is the return value of your factory function - i.e. the instance of your service. And I checked - it doesn't seem like I am missing a { - so, not sure what you mean
New Dev, thanks. I'm going completely bonkers. I think I've refactored to make it the way you recommended. My updated code is here pastebin.com/qJtR5b9d Now I'm getting a ERROR: Error: [ng:areq] Argument 'zmApp.MonitorCtrl' is not a function, got undefined. I bet its some semicolon or parentheses somewhere and I can't figure it out!
@user1361529, one error right away is that .then gets a response object - not data - see again the difference between .then and .success in my answer above. Other than that, if the code you posted is the whole code, then you need to do: var app = angular.module('zmApp.controllers', []); - notice the [] brackets.
Thanks - that is not why I'm getting an undefined zmApp.MonitorCtrl, however. If I delete the factory function and delete the factory invocation from MonitorCtrl, it works without runtime errors - so I bet its something inside the factory. This is not the full code, I'm instantiating zmApp.controllers with parentheses elsewhere I'll keep digging
|
1

try with this,here i am returning the promise as is

var app = angular.module('zmApp.controllers');

app.controller('zmApp.MonitorCtrl',  function($ionicPlatform, $scope,$http,ZMFactory)
{

            $scope.monitors=[];
            console.log("***CALLING FACTORY");
            ZMFactory.getMonitors().then(function(data)
            {
               $scope.monitors = data;
               console.log ("I GOT " +$scope.monitors);
            });

});



app.factory('ZMFactory',['$http', '$rootScope',function($http,$rootScope)
{
    //var factory = {};
    var monitors =[];
    return {
        getMonitors: function()
        {

          return  $http({
                    url:'http://myurl.com:9999/zm/index.php?skin=xml',
                    method:'post',
                    headers: {'Content-Type': 'application/x-www-form-urlencoded',
                               'Accept': '*/*',
                               },
                        transformRequest: function(obj) {
                               var str = [];
                               for(var p in obj)
                               str.push(encodeURIComponent(p) + "=" + encodeURIComponent(obj[p]));
                               var foo= str.join("&");
                               console.log ("****RETURNING "+foo);
                               return foo;
                        },
                        transformResponse: function(data)
                        {
                            var x2js = new X2JS();
                            var json = x2js.xml_str2json(data);
                            console.log ("***Transmogrifying XML to JSON");
                            return json;
                        },
                        data: {username:'xxx',
                               password:'xxxx',
                               action:'login',
                               view:'console'}

                      }) //http
                      .then(function(data)
                      {
                          console.log("****YAY"+JSON.stringify(data));

                          var subobj =data.ZM_XML.MONITOR_LIST.MONITOR;
                          var len = subobj.length;
                          for (var i =0; i< len; i++)
                          {
                           console.log ("HERE " + subobj[i].NAME);
                           monitors.push(subobj[i]);
                           }
                          // $rootScope.$broadcast ('handleZoneMinderMonitorsUpdate',monitors);
                           return monitors;
                        },function(error)
                        {

                           return error;
                        });

        }
    };

}]);

2 Comments

Thanks pranay. I wanted to avoid $q as I had read http already returns a promise - I would go this route if I did not get the model right in the previous way, which I managed to get right with the help from New Dev.
one more thing,i think transform request and response you should keep it in interceptors just to clean up the code

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.