24
votes

Since when using sql lite if you try and do a function at the same moment it throws an error, im just trying to make a function that will check if its executing, and if it is try again in 10 milliseconds, this exact function works fine if i dont have to pass any arguments to the function but im confused how I can pass the vars back into the function it'll be executing.

I want to do:

timer.addEventListener(TimerEvent.TIMER, saveChat(username, chatBoxText));

But it will only allow me to do:

timer.addEventListener(TimerEvent.TIMER, saveChat);

It gives me this compile error:

1067: Implicit coercion of a value of type void to an unrelated type Function

How can I get this to pass this limitation?

Here's what I've got:

public function saveChat(username:String, chatBoxText:String, e:TimerEvent=null):void
{
    var timer:Timer = new Timer(10, 1);
    timer.addEventListener(TimerEvent.TIMER, saveChat);

    if(!saveChatSql.executing)
    {
        saveChatSql.text = "UPDATE active_chats SET convo = '"+chatBoxText+"' WHERE username = '"+username+"';";
        saveChatSql.execute();
    }
    else timer.start();
}
5

5 Answers

27
votes

A function called by a listener can only have one argument, which is the event triggering it.

listener:Function — The listener function that processes the event. This function must accept an Event object as its only parameter and must return nothing, as this example shows:

function(evt:Event):void

Source

You can get around this by having the function called by the event call another function with the required arguments:

timer.addEventListener(TimerEvent.TIMER, _saveChat);
function _saveChat(e:TimerEvent):void
{
    saveChat(arg, arg, arg);
}

function saveChat(arg1:type, arg2:type, arg3:type):void
{
    // Your logic.
}

Another thing you can do create a custom event class that extends flash.events.Event and create properties that you need within.

package
{
    import flash.events.Event;

    public class CustomEvent extends Event
    {
        // Your custom event 'types'.
        public static const SAVE_CHAT:String = "saveChat";

        // Your custom properties.
        public var username:String;
        public var chatBoxText:String;

        // Constructor.
        public function CustomEvent(type:String, bubbles:Boolean=false, cancelable:Boolean=false):void
        {
            super(type, bubbles, cancelable);
        }
    }
}

Then you can dispatch this with properties defined:

timer.addEventListener(TimerEvent.TIMER, _saveChat);
function _saveChat(e:TimerEvent):void
{
    var evt:CustomEvent = new CustomEvent(CustomEvent.SAVE_CHAT);

    evt.username = "Marty";
    evt.chatBoxText = "Custom events are easy.";

    dispatchEvent(evt);
}

And listen for it:

addEventListener(CustomEvent.SAVE_CHAT, saveChat);
function saveChat(e:CustomEvent):void
{
    trace(e.username + ": " + e.chatBoxText);
    // Output: Marty: Custom events are easy.
}
11
votes

Actually, you can pass additional parameters to an event listener without creating a custom event by using Actionscript's dynamic function construction.

private function addArguments(method:Function, additionalArguments:Array):Function
{
  return function(event:Event):void {method.apply(null, [event].concat(additionalArguments));}
}

When setting up the closeHandler for the Alert window we call the addArguments() method and pass in an array continaing all of the parameters we want to pass to the closeHandler. The addHandler() method will return the function we will call when the Alert window closes with the parameters included.

protected function btnOK_clickHandler(event:MouseEvent):void
{
  Alert.show("Would you like to reverse the text you just entered?", "", Alert.YES | Alert.NO, null, addArguments(alertCloseHandler, [txtInput.text]), null, Alert.YES);
  txtInput.text = "";
}
10
votes

1067: Implicit coercion of a value of type void to an unrelated type Function

Pay due attention to the error you got: it says that a Function is a type and that addEventListener() wants it. Although your listener returns void, it is a Function! So, what about returning the listener?

timer.addEventListener(TimerEvent.TIMER, saveChat(username, chatBoxText));
function saveChat(username:String, chatBoxText:String):Function {
  return function(e:TimerEvent):void {
    // Do everything that uses "e", "chatBoxText" and "username" here!
  };
}

Simple like this. It works for any kind of event. And no closure issues.

Note on removeEventListener():

Don't try to do timer.removeEventListener(TimerEvent.TIMER, saveChat(username, chatBoxText)). It won't recognize your function because you'll be passing a new one on it every time you use saveChat(). Instead, just take its reference out into a variable and you're done:

var functionSaveChat:Function = saveChat(username, chatBoxText);
timer.addEventListener(TimerEvent.TIMER, functionSaveChat);
//trace(timer.hasEventListener(TimerEvent.TIMER));
timer.removeEventListener(TimerEvent.TIMER, functionSaveChat);
//trace(timer.hasEventListener(TimerEvent.TIMER));
1
votes

You can try this:

var timerHandler:Function = function (event:TimerEvent):void
{
   saveChat(username,chatBoxText,event);
}

timer.addEventListener(TimerEvent.TIMER, timerHandler);
1
votes

Above calling saveChat(arg, arg, arg) it's not for me, i need to pass arguments that i dont have in this method but i have another solution

Im always using additional method passParameters to adding new arguments:

public function passParameters(method:Function,additionalArguments:Array):Function
{return function(event:Event):void{
    method.apply(null, [event].concat(additionalArguments));}
}

explanation of this is here - its simple and always work http://sinfinity.pl/blog/2012/03/28/adding-parameters-to-event-listener-in-flex-air-as3/