It's all about the answers!

Ask a question

How to get a dojo handler to return value to calling function?


1
1
SEC Servizi (93622142) | asked Jul 06 '16, 9:53 a.m.
edited Jul 06 '16, 10:07 a.m. by Ralph Schoon (55.5k23642)
We would be able to return a value from our function when this value has to come from an asynchronous service call:
getContributor: function(userId) {
	var contributor;
	var args = {
		searchField: "userId",
		searchTerm: userId
	};
	var handler = {
		success: dojo.hitch(this, function(responseObj) {
			contributor = responseObj.elements[0];
		}),
		error: function(errorObj) {
			console.log(errorObj.message);
		}
	};
	var serviceResponseHandler = new com.ibm.team.repository.web.transport.ServiceResponseHandler(handler, "success", "error");
	com.ibm.team.repository.web.client.internal.AdminClient.getContributors(args, serviceResponseHandler);
	return contributor;	// undefined
}
In this case, the returned value is "undefined" because the service call is not executed yet (i.e., it is an asynchronous call).
Any advice on how to make a sync call as in 'dojo.xhrGet({ ..., sync: true });'?
Thanks in advance.

2 answers



permanent link
Jonas Studer (207816) | answered Jul 08 '16, 3:36 a.m.
Hello Mister Servizi,

First you should be aware what asynchroneous  means.
As soon as you start an async process it's like a new Thread.
Method A --> AsyncMethodA (Cant return to Method A because it isnt the same "process-Scope"[probably a wrong word])

So, if you wanna use async methods you'll have to adapt their behaviour.
And thats, where the responseHandler comes into the play.

All 3 calls will now land in the same method.
How you will handle it, its your choice.

Method A --> AsyncMethodA --> ResponseMethodA
Method A --> AsyncMethodA --> ResponseMethodA
Method A --> AsyncMethodA --> ResponseMethodA

If you NEED a return value, use a synchroneous get.

Problem:
main: function(){
    //test NEVER gets the value
    var test = this.getContributor("blabla");
}

getContributor: function(userId) {
    var contributor; //1: NOT THE SAME CONTEXT
    //var contributor2 //2: Keep the same context
    var args = {
        searchField: "userId",
        searchTerm: userId
    };
    //var self = this; //2: Here we give the method a possibility to keep the scope
    var handler = {
        success: dojo.hitch(this, function(responseObj) {
            contributor = responseObj.elements[0]; //1: AS THIS
            this.contributor = ... //1: This would be the same var as outside
            //self.contributor2 //2: This is now the same Object
        }),
        error: function(errorObj) {
            console.log(errorObj.message);
        }
    };
    var serviceResponseHandler = new com.ibm.team.repository.web.transport.ServiceResponseHandler(handler, "success", "error");
    com.ibm.team.repository.web.client.internal.AdminClient.getContributors(args, serviceResponseHandler);
    return contributor;    // undefined //1: This stays undefined
    return contributor2 //2: Still not working, because it will not be setted when it's returned
                        //2: You can check this if you'll add a wait/sleep method before the return
}

Solution:

var transactionsInAction = null;
var responseStorage = null;

//A little idea how to handle async calls
main: function(){
    this.transactionsInAction = 0;
    this.responseStorage = [];
    this.getContributor("blabla1");
    this.getContributor("blabla2");
    this.getContributor("blabla3");
}

dataResolved: function(contributor, transactionId){
    this.responseArrays[transactionId] = contributor;
    //this.responseArrays.push(contributor); //Without transactionId
    this.transactionsInAction--;
    if(this.transactionsInAction < 1){ //No transactions in action
        this.doWhatYouWantOrNeed();
    }
}

getContributor: function(userId) {
    var args = {}; //I keep it blank to save space
    //Better would be to use deferred but hitch works too, to keep the scope
    var handler = {
        success: dojo.hitch(this, function(responseObj) {
            var transactionId = this.transactionsInAction; //This could help to keep track which data are when loaded but not needed.
            this.dataResolved(responseObj.elements[0], transactionId); //This sends the response to the given method
        }),
        error: function(errorObj) {
        }
    };
    this.transactionsInAction++;
    var serviceResponseHandler = new com.ibm.team.repository.web.transport.ServiceResponseHandler(handler, "success", "error");
    com.ibm.team.repository.web.client.internal.AdminClient.getContributors(args, serviceResponseHandler);
}

permanent link
SEC Servizi (93622142) | answered Jul 22 '16, 10:25 a.m.
edited Jul 22 '16, 10:27 a.m.
Hello Jonas,
thank you for your answer. In your opinion, a naïve solution like this one below is not possibile?
getContributor: function(userId) {
	var contributor;
	var args = { ... };
	success: dojo.hitch(this, function(responseObj) {
			contributor = responseObj.elements[0];
		}),
		error: function(errorObj) {
			console.log(errorObj.message);
		}
	};
	var serviceResponseHandler = new com.ibm.team.repository.web.transport.ServiceResponseHandler(handler, "success", "error");
	com.ibm.team.repository.web.client.internal.AdminClient.getContributors(args, serviceResponseHandler);
	while (!contributor) {
		// wait until outer var get a value?
	}
	return contributor;
}
	
Thanks in advance.
Cheers.

Comments
Jonas Studer commented Jul 25 '16, 2:02 a.m.

Hello Mister Servizi,

It sure worth a try!
The downside on this code is, that it'll block the whole Process till the wished data (contributors) are retrieved.

But why keep it sequentially? Instead of A -> WAIT -> B
Why not going over a third method? A -> A-helper -> B
This way it would be non blocking code.

But if you just need some Field Values (That's why I'm guessing you want to use the return) It might work the way you suggested.

Another Idea could be to work with deferred.

getContributorData: function(userId) {
    var deferred = new dojo.Deferred();
    //Your code
    //Maybe its possible to directly return from the succees method since hitch keeps the same context.
    //return responseObj.elements[0];
    return deferred;
}


Jonas Studer commented Jul 25 '16, 2:03 a.m.
getContributor{
var
deferred = getContributorData(); deferred.then(function(value){ // Do something on success. }, function(error){ // Do something on failure. });
}

Your answer


Register or to post your answer.