Bertrand
Bertrand

Reputation: 13570

Javascript OOP - Returning a value from function that's inside an object's method (nested function)

I'm having troubles to return a value from a function that is inside an object's method. How could I do this? Let me explain with code.

function ObjPerson() {

    this.getPerson = function() {

         function queryDB() {
             //run query and pass result data to success or error functions
         }

         function success(data) {
             //process data 
             return data;  
         }

         function error(errorData) {
           //process error
         }

         queryDB();
    }
  }

 var person = new ObjPerson;
 var userData = ObjPerson.getPerson();

The problem is that nothing is being returned from the getPerson() method. What would be the best way to do this?

Thanks!

Upvotes: 1

Views: 1350

Answers (4)

Robert Koritnik
Robert Koritnik

Reputation: 105059

Return the value if this is a synchronous function

function ObjPerson() {

    this.getPerson = function() {

        function queryDB() {
            //run query and pass result data to success or error functions
        }

        function success(data) {
            //process data 
            return data;  
        }

        function error(errorData) {
          //process error
        }

        return queryDB(); // HERE'S THE CHANGE
   }
 }

var person = new ObjPerson(); // always use parentheses
var userData = person.getPerson(); // ERROR: getPerson is instance function

But if this function is async, then you should be doing it a bit differently. Unfortunately you won't be able to just call:

var userData = person.getPerson();

because by the time the assignment is made, your async call will likely not return yet... So your userData assignment should be assigned after the async call. (tell us what async lib are you using)

Other code smells in your example

But your code has other smells as well. Your inner functions queryDB, success and error functions are defined within closure and for the sake of readability they should be defined as local scope variables:

var success = function (data) {
    // process data
    return data;
}

Upvotes: 4

JayC
JayC

Reputation: 7141

If queryDB is asynchronous, it is good advice (especially if you are using jQuery) for queryDB and hence getPerson (with modification to your code) to return a "promise" type object. From that promise you can attach more success/failure/completed type callbacks to continue processing. In jQuery, those kid of callbacks can be done with done, fail, always as in:

   var person = new ObjPerson;
   var userDataPromise = ObjPerson.getPerson();
   userDataPromise.done(function(person){
      //deal with person object here
      //
   }).fail(function(errorobj){
      //deal with error
   }).always(function(){
      //deal with completion
   });

Now, if you were using the jQuery library, you could return the promise returned in the ajax call. That's not what I'll advise. In all likelihood, you have some strict requirements about how your person is to be invoked. Furthermore, you really don't care to have other parts of your code know that you're doing ajax or localDB or anything... they just need access to the person.

So here's a rough sketch about how you can complete your code to do that.

function ObjPerson() {
    function getData (args,success,fail){
        //somehow get your data.  We'll assume it doesn't return promises
    } 
    this.getPersonPromise = function() {
        var returnedPromise = $.Deferred();

        getData(args,function(data){
           //success callback
           //process data (assume PersonCustomData is defined elsewhere)
           var person = new PersonCustomData (data)
           returnedPromise.resolve(person);
        }, function(error) {
           //failure callback, return custom errors, or maybe 
           //just return original error if lazy or don't quite know all methods
           //of failure or something.
           var errorObj = ...
           returnedPromise.reject(errorObj);

        });
        return returnedPromise;

    }
  }

 var person = new ObjPerson;
 var promise = ObjPerson.getPersonPromise();
 person.done(function(person){
    //do more stuff with PersonCustomData instance
 }).fail(function(errorObj){
    //oops
 })

etc. That way you do not have to pass around callbacks until after the fact. Very cool.

Upvotes: 1

trakos
trakos

Reputation: 841

I've never used phonegap, but basing on its documentation:

When the executeSql method of a SQLTransaction is called it will invoke it's callback with a SQLResultSet.

executeSql, which you probably use, is asynchronous. That means, that you have to change it, for example, instead of:

 var person = new ObjPerson;
 var userData = ObjPerson.getPerson();
 // something here using userData

you have to:

function ObjPerson() {

    this.getPerson = function(requestSuccesfullCallback) {

         function queryDB() {
             //run query and pass result data to success or error functions
         }

         function success(data) {
             //process data 
             requestSuccesfullCallback(data);  
         }

         function error(errorData) {
           //process error
         }

         queryDB();
    }
  }

 function callback(userData)
 {
      // something here using userData
 }

 var person = new ObjPerson;
 ObjPerson.getPerson(callback);

Upvotes: 1

Naigel
Naigel

Reputation: 9644

function getPerson doesn't return nothing, you should use return in order to assign a value (note that return data return a value for the function success)

Upvotes: 1

Related Questions