Is it possible to 'chain' functions? Say, I have a serverclickhandler and then would like to invoke another function after it right away. How do I go about it?
Thanks.
To have a second handler executed after the first one you just need to call it directly from your first handler, e.g.
var app = null;
function firstHandler(e) {
if( app == null )
app = UiApp.getActiveApplication();
//do your thing
//now, instead "return app;" you return the second handler
return secondHandler(e);
}
function secondHandler(e) {
if( app == null )
app = UiApp.getActiveApplication();
//do your job
return app;
}
I placed the app var on a global scope so you can get it only when necessary (sharing it between the functions without explicit passing it), saving a possibly costly and unknown behavior (to me at least) of a second getActiveApplication() call.
Not sure I understood exactly your question but serverhandlers to which you refer are precisely made for that... (see doc)
Note that you can assign multiple handlers to UI elements to trigger different functions and eventually chain them.
Related
I have a function in Adobe Flex 4 (ActionScript 3) that accepts an object and returns an ArrayCollection...
If a certain global variable is set to true, I want the function to delay itself for 3 seconds before running. Otherwise I want the function to run as normal.
The problem is, if I use a Timer, that timer calls a separate function, and that function cannot return anything to my calling function, nor can the function it calls accept any parameters, so it's not like I can call my own function recursively after the TimerComplete event fires... And a recursive call wouldn't work anyway, because it would return the ArrayCollection to the timer-result function, not to the original calling function...
I need a delay within the function, not a delay that causes me to go outside that function. But I cannot figure out how to do it.
Something like this is what I need to do:
private function createArrayCollection(myObject:Object):ArrayCollection {
var myArrayCollection:ArrayCollection = new ArrayCollection();
if (globalWaitBoolean) {
//delay here for 3 seconds, somehow
}
//Here I do the stuff that uses the info in myObject to figure out what to
//put into the ArrayCollection I want to return
return (myArrayCollection);
}
So... Any ideas on how to accomplish this without calling an external Timer function that cannot return an object back to my original function?
Thanks,
The way you want it you will have your whole application to lag for 3 seconds, unresponsive to any user input and external events. But it is possible, sure:
import flash.utils.getTimer;
private function createArrayCollection(myObject:Object):ArrayCollection
{
var myArrayCollection:ArrayCollection = new ArrayCollection;
if (globalWaitBoolean)
{
var waitUntil:int = getTimer() + 3000;
// Method getTimer() returns time in ms passed since app start.
// So you just have to wait until it is greater than appointed time.
while (getTimer() < waitUntil)
{
// Do nothing.
}
}
return (myArrayCollection);
}
Still, if you want to do it in a correct way of doing it:
import flash.utils.setTimeout;
private function callerMethod():void
{
// Blah blah blah.
// ...
// Finally.
createArrayCollection(sourceData, asyncResult);
}
private function createArrayCollection(myObject:Object, handler:Function):void
{
var result:ArrayCollection = new ArrayCollection;
if (globalWaitBoolean) setTimeout(handler, 3000, result);
else handler(result);
}
private function asyncResult(source:ArrayCollection):void
{
// The rest of your processing code.
}
Normal (synchronous) code flow would not return until the value is prepared, so should you desire to actually wait for 3 seconds while not allowing your app to do anything, use getTimer() approach from #Organis's answer. If you'll go for an asynchronus result, you'll need to face and overcome some more problems.
First, when do you expect your returned ArrayCollection to actually arrive. Speaking of code design, asynchronous code requires a whole lot of assumptions, thread safety etc etc, and even while AS3/Flash does not have true multithreading unless you count Workers, the code flow with events is not as obvious. So, whoever called your createArrayCollection() MUST NOT expect value returned from it right away. So, speaking about your direct question, NO, you can't avoid timers of some sort if you desire a responsive application. But you can use them with an approach that would involve an indirectly returned result.
Second, whether there might be concurring requests for more array collections from objects if your app would require these - you have to prepare for any kind of interference that might be caused by this. Say your function is triggered by a button click - what if that button would get clicked more than once in 3 seconds?
Third, actual route to processing code is not direct with asynchronous return. You need either a callback, an event handler (which is essentially a semi-native callback), a code that periodically checks for value presence (enter frame handler, etc) or a similar trick to gather the value that's returned asynchronously, and then transfer it to any relevant code that would process it further. Therefore, you would need to design an interface capable of receiving complex data (source object forward, array collection backward) and then carefully test it against all the possible cases and flaws.
An example of implementing all that is very long, I'll try to outline it somehow. Ler's assume you have a sort of "server" class that accepts requests for data and processes it synchronously (no wait) or asynchronously (wait). It accepts a source object of type "T" and provides a newly created object of type ArrayCollection, supplied as a parameter to whatever callback function sent to it. Also it accepts a delay (a simple way to show sync/async return would be a boolean, but why not getting an int?) as a parameter, and guarantees (to the extent of event model limitations) that after this delay the callback will be called ASAP. The architecture will then look like this:
class Processor {
Dictionary requests; // here all the requests that are delayed will be stored
public function dpr(source:T,callback:Function,delay:int=0):void{...}
// creates requests and stores them
private function syncProcess(source:T):ArrayCollection {...}
// whatever routine you want to get variably delayed
private function processTimeout(e:Event=null):void {...}
// processes events from "setTimeout()" and calls callbacks
}
Note that asynchronous approach forced to create three more entities than a synchronous one. First is the request holding structure (the dictionary here), second is timeout event handler, third is whatever callback you'll desire to get called when the data is ready. The code flow would go like this:
Synchronous call would result in the callback directly called from within the class: request->processTimeout->syncProcess()->callback. Asynchronous call will have the callback called from within Timer::timerComplete event handler via setTimeout called within request, with data that originally came from request stored in requests.
You could use an embedded/inline function:
private function createArrayCollection(myObject:Object):ArrayCollection {
var myArrayCollection:ArrayCollection = new ArrayCollection();
if (globalWaitBoolean) {
var milliseconds:int = 3000;
//delay here for 3 seconds
setTimeout(function()
{
//Here I do the stuff that uses the info in myObject to figure out what to
//put into the ArrayCollection I want to return
return (myArrayCollection);
},
milliseconds);
}
else
{
//Here I do the stuff that uses the info in myObject to figure out what to
//put into the ArrayCollection I want to return
return (myArrayCollection);
}
}
The inner function will have access to all local vars of the outer function.
Basically I want to check if a user exists in a database using AMF (and that works great!). But then I want to return the boolean value to another function (in another class) that originally called the "checkUserExistance" function. But, since the database connection isn't immidiate, this function will always return a false value (even if "result" is true). So I would like to have the return-line inside the "onUserChecked"-function but that of course gives me an error. I thought I could create an eventListener, but then, the "return userExists"-line would also have to be inside another function, which doesnät work(?)... What can I do?
public function checkUserExistance(username:String) {
var responderBOOLEAN:Responder = new Responder(onUserChecked, onFault)
var userExists:Boolean = false;
connection.connect(gateway);
connection.call("User.checkUser", responderBOOLEAN, username);
connection.close();
function onUserChecked(result:Boolean):void {
userExists = result;
}
return userExists;
}
I'm sorry but you are trying to force an Asynchronous call to a Synchronous one and this is WRONG.
See here
You should learn how to handle events in the correct way.
What can i suggest you that helped me a lot is this
The only true answer here is to save userExists as a member variable, and dispatch event when the server returns you a response. The client side of the things should be similar to:
// add listener, ServerEvent is a custom event (see below)
server.addEventListener(ServerEvent.CHECK_RESPONSE, onCheckResponse);
server.checkUserExistance('username'); // start the query
function onCheckResponse(e:ServerEvent):void {
if (e.userExists) {
}
}
// inside server class
function onUserChecked(result:Boolean):void {
userExists = true;
dispatchEvent(new ServerEvent(ServerEvent.CHECK_RESPONSE, userExists));
}
/* ServerEvent is a custom class that extens Event
Such classes are used so you can pass special properties in them
via constructor (pass data, store it into member variable)
and through getter for that variable.
If you don't like it, simply add/dispatch Event.COMPLETE
and use public property to get userExists from server
*/
I am using FlashSocket on my client side to make calls to socket.io on node.js server.
But i want specific values and function references to be available in the socket event listeners.
One approach that came to my mind was to pass the required values along with the request and make the server to send those parameters back along with the data. But that doesn't seem to help since I need the function handlers to be returned as well with the result.
The way i am doing it with http request is:
var token:AsyncToken = _service.send(item.params);
token.id = _tokenId;
token.params = item.params;
token.handler = item.resultHandler; // this would be called later in result or fault event handlers.
Is there a way to achieve this in flex sockets?
Thanks in advance.
You could use AsyncResponder class and anonymous functions.
var token:AsyncToken = _service.send(item.params);
token.addResponder(new AsyncResponder(
function(event:Object, token:Object = null):void {
// result handler, it has access to item.params, etc.
},
function(error:FaultEvent, token:Object = null):void {
// fault handler, it has access to item.params, etc.
}
));
I want to add listeners to google map events, but not using anonymous functions but named, external functions as this happens inside a loop, I do not want to define an anonymous function right there, but instead use a named, external function:
Not:
for (...) {
googleMap.event.addListener(instance, eventName, function() {...});
}
But rather sth. like:
doSomething = function(parameter1, parameter2...) {
...
}
for (...) {
googleMap.event.addListener(instance, eventName, params, doSomething);
}
When "instance" is a google map marker, I can add the parameter(s) to the marker using marker.set(paramName, paramValue) and then access the parameters inside the event handler function via this.paramName, but is there any other way to pass values to the event handler function when I don't want to use an anonymous one?
Any advice welcome, Roman.
I had the same problem. Here is a solution. It genuinely avoids the create function in a loop problem, by using the pattern described here
In JavaScript, what are specific reasons why creating functions within a loop can be computationally wasteful?
Which I call the "function factory" pattern.
The other ingredients are that inside the function "this" refers to the object which raised the function (the thing on the map which was clicked, or whatever), and because JavaScript is completely dynamic, you can attach additional properties at will to the thing which was clicked, and query them by calling this.blah inside the function
function doSomethingHandlerFactory(){
var f = function(event){
//do something, for example call a method on a property we attached to the object which raised the event
this.blah.clicked(event);
};
return f;
}
//add a property to the google overlay object (for example a polyline which we've already set up)
thePolyline.blah = ...;
//get a handle for a function, attach the event (in this case to a polyline), and keep
//a reference to the event (in case we want to call removeListener later). The latter
//is optional.
var f = doSomethingHandlerFactory();
var ev = google.maps.event.addListener(thePolyline, 'click', f);
I hope this helps someone out.
How about wrapping your named function in an anonymous function:
google.maps.event.addListener(instance, eventName, function() { doSomething(parameter1, parameter2,...) });
I have written a function which is recursively called. I have maintained an array in which values are pushed with a listener of an event. But the problem is function is returned first without array increment and the listener is executed later.
public function getAllChilds(seltem:XML, allChilds:Array): Array
{
if(//the childs of selected item if need to retrive from server)
var viewChildrenJobsService : HTTPService = new HTTPService();
viewChildrenJobsService.url = // here is my url ;
viewChildrenJobsService .addEventListener(ResultEvent.RESULT, function(event:ResultEvent):void {
// now on this result event i got all childs of selected item.
for each(var childJob :XML in seltem.children())
{
allChilds.push(childJob);
if (//the childs of childJob need to retrive from server)
allChilds = getAllHierarchicalChilds(childJob, allChilds);
}
});
return allChilds;
}
Is there any way to overcome this problem so that the function will return after the completion of the event?
ok , you are returning allchilds before the Result Event. You erase the original question ;) , so i dont remember if your problem was this.
Try to split the function : First the request, then get the value of allChild.
and yes ... is better to write (and paste) good formatted code : its easier to understand.