EventProxy.as : Proxying Events

One of the issues I ran into while building the MXNA WebService example app, was that both the ComboBox and DataGrid both broadcast “change” events. This meant that I could not have a separate function to listen for each event (and have the functions run within the scope of the feedView class).

There were two solutions to this. The first was to have a switch statement in my change event handler, that checked the eventObt.target property to see where the event came from. I could then dispatch the call as appropriate. Here is an example of what the event handler would look like:

[code]private function change(eventObj:Object){switch(eventObj:target){case myDataGrid :{//the datagrid event firedbreak;}case myComboBox :{//the combobox event firedbreak;}}}[]

However, I personally don’t like this as it means I have to define an event handler, maintain a switch statement, and then define individual methods to handle the events. Jesse Warden posted a good example of this on his weblog.

The other option was to create a simple class that basically proxies the events to different scopes and methods. I like this solution as it felt a little cleaner to me. I put together a simple proxy class (EventProxy) based on a FlashCoder’s post by Sam Neff.

Here is an example of how it works (from MXNAFeedView.as):

[code]public function onLoad(Void):Void{categoryProxy = new EventProxy(this, “onCategorySelect”);category_cb.addEventListener(“change”, categoryProxy);feedGridProxy = new EventProxy(this, “onFeedGridSelect”);feedDG.addEventListener(“change”, feedGridProxy);}//broadcast by ComboBox when user selects an item in the comboprivate function onCategorySelect(eventObj:Object):Void{//ComboBox change event fired}//broadcast by the DataGrid when the user selects a rowprivate function onFeedGridSelect(eventObj:Object):Void{//datagrid change event fired}[/code]

This does two things:

  1. It allows change events from two different components to be dispatched to two methods.
  2. It allows the event handlers to be called within the scope of the containing class (in this case MXNAFeedView)

Here is the code for the class:

[code]/*EventProxy classAllows:-scope of events to be changed-events calls to be proxied to arbitrary functions*/class com.macromedia.mesh.events.EventProxy{private var receiverObj:Object;private var funcName:String;/*Constructor:-receiverObj : the receiverObj in which the event will be called-the function name to be called in response to the event*/function EventProxy(receiverObj:Object, funcName:String){this.receiverObj = receiverObj;this.funcName = funcName;}//this is called before the event is broadcast by the componentsprivate function handleEvent(eventObj:Object):Void{//if not function name has been definedif(funcName == undefined){//pass the call to the event name methodreceiverObj[eventObj.type](eventObj);}else{//pass the call to the specified method namereceiverObj[funcName](eventObj);}}}[/code]

Post any suggestions or bugs in the comments.

23 Responses to EventProxy.as : Proxying Events

  1. Brian says:

    Yeah, I never liked that behavior of the 2k4 components. Good solution. Also check out Grant Skinner’s GDispatcher for a slightly more feature complete EventDisapatcher (that gets around this issue) for your own uses.

  2. nig says:

    Second guessing the w3c… tsk, tsk, tsk.

  3. marK says:

    Why the SOAPCall.addHeader() isn’t exist in WebServices package ?

  4. Something must be in the air regarding proxy listeners… I just finished a post on my discussion board (http://flashsim.infopop.cc/6/ubb.x?a=tpc&s=768608087&f=1106035535&m=7666077455&r=7666077455#7666077455 ) on a similar topic.I started the flashcoders post you referred to because I wanted a way to specify a listener in the property panel (by string name). I can see that your approach is non-invasive by creating the proxy listener. Since I am building my own component set from the ground up (well, from UIComponent up), I wanted to have the luxury of permitting the developer to change the event names at initialization time (in the property inspector or programmatically via attachMovie’s initObject). In this way, each instance decides which event it wants to generate to distinguish itself from other instances of the same class.If you’re having trouble sleeping, take a look at my post…-jonathan

  5. Cort says:

    I just wanted to mention that I like the switch statement better and try to explain why. Perhaps someone can clear up my ignorance and I’ll learn something as a result, but since Java became so popular, I’ve seen this aspect of it that I don’t like being used more and more.That is the making of straightforward conditional or procedural logic into objects, and eventually, architecture.I see it as making the code less readable. It turns one simple object that is a coherent component into into a group of objects so that you can’t just follow the code by scanning the code blocks as easily.IDE’s in general do a better job of displaying text than structure. So as lame as using text indentaion may seem as a main visual cue for what is going on within a block of code(as with a switch statement), the alternative of turning each block into it’s own object, looses the visual cue for which block is for the datagrid and which is for the combobox.In your first version, those blocks of code are clearly labeled by the switch statement. In the object version the difference is buried in the name of an argument in the constructor.Note also that you’ve taken a useful piece of information that this is a “select” event and merged it into in the name of the event.What happens when things get a little more complex and you add two more types of events? You’ll end up with a lot more blocks that require maintenance than with the switch statment.Also, what will be the next step if all the targets have an event that you respond to in the same way? With the switch statement you can just check for that event before reaching the switch and handle it for all the targets.On the other hand, if you follow the same process as described here and extract it into another object with the other objects inheriting from it. Etc, etc…what you end up with in the end is the equivalent of a switch statement object or a switch statement architecture.If it is a part of a larger framework where select objects and mouseover objects and click objects are automatically generated and organized for some larger purpose I can understand it, but for an application I’d prefer the switch.What I really think it comes down to is the granularity of objects. The main benefit of programming with objects is not code reuse as is often stated. Libraries of C code were just as reusable as Objects. I believe that Java object libraries typically go through many more changes than simpler C libraries did.The point of using objects in my mind is to take larger conceptual feature sets and group them into cohesive objects in order to reduce the overall complexity. So that all you need to do is focus on the object’s interface.If an object isn’t sufficiently complex that creating it is simplifing the overall code structure and reducing the total number of code blocks that you have to interface with, I’d prefer that folk would stick with the primitives and language elements.Thanks for listening. It’s just my two cents. But I thought to state it in case I am missing something.Cort

  6. Dominick says:

    Cort:The switch statements are useful for small applications that don’t require much functionality. Anything larger would completely obfuscate the code. For instance, if there were two lines in between every case statement it looks neat.//the datagrid event firedvar vh = new gridViewHelper();vh.setDataProvider(dp);However, if the functionality consists of a few hundred lines, then you no longer have a complete visual of the switch statement. It then becomes less obvious. This is where the Jesse Warden’s EventProxy comes in to save the day. We now can logically create these functions that will be appealing even with a great number of LOC (lines of code)…Also, the EvenProxy class can be tailored to abstract out some functionality from the calling event. Other helper functions could be called within this class so that they are not added to the callback function.Last, it won’t be confusing to anyone who understands the class. A developer might need to take one glance at the class, and they may immediately see the benefits. Of course, there might be comments above Mikes code that give an indication of the functionality of the EvenProxy class. For example:public function onLoad(Void):Void{//the EventProxy class allows for seperate//callbacks to take place on the event calledcategoryProxy = new EventProxy(this, “onCategorySelect”);category_cb.addEventListener(“change”, categoryProxy);feedGridProxy = new EventProxy(this, “onFeedGridSelect”);feedDG.addEventListener(“change”, feedGridProxy);}Something along those lines. Hope this helps.

  7. Dear Cort and Dominick,I can see the argument both ways, and that’s why I made my post above. What I came up with was a slightly different idea — why not allow developers to change the event name that the component generates, even on an instance-by-instance basis?In that way, if you know your (centralized) event handler will see the same event from two different components (whether or not they are instances of the same class), you can easily name the event differently.This does require a foundational change in the architecture, but I think the added flexibility is worth it (though perhaps the motivation for changing event names is better left as an advanced topic).In terms of the provided example, it would be something like this:// somewhere in initialization you’d have had:// category_cb.evtChange = “cbChange”;// feedDG.evtChange = “dgChange”;public function onLoad(Void):Void{category_cb.addEventListener(“cbChange”, this);feedDG.addEventListener(“dgChange”, this);}This would allow you to use Dominick’sthis.cbChange = …this.dgChange = …or Cort’sthis.handleEvent = function (ev) {…switch (ev.type) {case cbChange:…case dgChange:…// or back to just ‘change’ and have it sort out the instance}-jonathan

  8. Cort says:

    Hi Dominick,Thanks for the response.I think I’d like to see the 200 line switch statement and the equivalent eventProxy version.A few hundred lines of straightforward code is still better in my mind than a thousand objects with a nest of inter-relationships.If every component is going to have an object for every type of event “onCategorySelect”, “onCategoryDelete” “onCategoryEdit” etc, you get some exponential growth, don’t you. Especially if there are some things that all these objects do.When one’s switch statement is getting too long for no good reason, there should be other options than going object happy.A third approach that I’d like to see folk think about more is to treat this eventhandler or controler more like a simple parser that takes objects as tokens and calls a function that performs the same action on each based on its event type and event properties. That’s a good way to reduce complexity at a bottleneck point like this without creating lots of objects and a framework to handle it.A fourth approach for when the dataGrid class is going to respond sufficiently differently from the combobox class is to use the structure of the components to greater effect. The dom has events where they are either caught or forwarded up the hierarchy, which is a method that keeps things simpler.Perhaps that is what this eventProxy will enable and I just need to see a more complex example, but I do want to remind folk that there is a price to pay as well anytime simple logic is turned into architecture.-Cort

  9. Cort says:

    Hi Jonathan,Yes, I agree with that.I’ll look at your listenerPlay and Mike’s web service example app( and Grant and Jesee’s things) and see if I can be more concrete about the parser notion.-Cort

  10. mike chambers says:

    >why not allow developers to change the event name that the component generates, even on an instance-by-instance basis?That is essentially what the proxy does.mike chambersmesh@macromedia.com

  11. mike chambers says:

    >A few hundred lines of straightforward code is still better in my mind than a thousand objects with a nest of inter-relationships.You only use the Proxy in one place, which is when you register for the event.If I used a Switch statement, i would just use it to delegate the events to the appropriate function anyways. using the proxy essentially does that work for me.An personally, I find the code a lot more straight forward to follow. Basically, you can look at it and know that an event is broadcast and goes to a specific method.As opposed to a switch, which is you know an event is broadcast, goes to a method, but then you have to then go look into that method and the switch to determine where it goes next.Lets look at a bare bones example of each:/******************Using Proxy*******************/categoryProxy = new EventProxy(this, “onCategorySelect”);category_cb.addEventListener(“change”, categoryProxy);public function onCategorySelect(eventObj:Object):Void{}And here it is using the switch statement/******************Using Switch*******************/category_cb.addEventListener(“change”);private function change(eventObj:Object){switch(eventObj:target){case category_cb :{onCategorySelect(eventObj);break;}}}public function onCategorySelect(eventObj:Object):Void{}They both do essentially the same thing, except the proxy basically takes out an entire (potentially long and confusing) step.Anyways, I am not suggesting either way is “bad”. I personally like using the proxy method, but I don’t think there is anything inherently wrong with using a big switch statement.mike chambersmesh@macromedia.com

  12. >> why not allow developers to change the event name that the component generates, even on an instance-by-instance basis?> That is essentially what the proxy does.your proxy does it exactly and only on an instance-by-instance basis, but I’m suggesting that it may be preferable to give the added option of doing it implicitly for all instances of the class.

  13. Jason says:

    Changing the event name for all instances of a class just puts you back in the same boat – it works fine if you only have one instance of that class on the ‘stage’, or multiple instances that all do the same thing.But once you get into having multiple instances of a class on the ‘stage’, dispatching the same events to the same listener but doing different things with them, changing the events dispatched does very little to actually help your code. Yes, ok, now you can handle any listbox changes with a single event handler, and any datagrid changes with a single event handler, but you still end up with a large switch statement inside that event handler to tackle the differing functionality for each instance that broadcasts the event.What you’d use an event proxy for is essentially when you have multiple objects broadcasting the same events, but you want to have a central object handle those events. Instead of looking at it from the perspective of ‘I’m handling a click event’, you want to to be looking at it from the perspective of ‘I’m handling button X’s click event’. So, you define the method/function that should execute when that button gets clicked, and instead of setting the object with the functionality up as the event listener, you set up an event proxy to handle the event and push it back to the object with the functionality.While this may seem somewhat roundabout, I think that in the end it does make the code more readable and understable. You’re creating sub-objects to handle catching the events, and propagating those up to the main object to handle them. Hence the ‘proxy’…This may be somewhat obvious from what has already been posted, (and/or somewhat less coherent). But I think most of those with objections to the idea of ‘objecting it out’ will find that as the complexity of their applications increase, so will the benefits of ‘objecting it out’.Incidentally, I’ve built something kind of like this for Remoting calls…will probably post the code in the near future…used it very successfully on the flashinthecan site (http://www.flashinthecan.com)

  14. mike chambers says:

    test

  15. Choosing a Flash Event Engine That’s Right For You

    What event engine is right for you? Read on to find out! Careful, she’s a long one……

  16. iS says:

    Thank you for this

  17. Creek Cache says:

    Thanks for great site

  18. trannysurprise ally | trannysurprise angel | trannysurprise angelique | trannysurprise ariana | trannysurprise barbie | tranny surprise brooke | tranny surprise dalia | tranny surprise janira | tranny surprise jenny | tranny surprise kittie | tranny surprise meiling | tranny surprise nikita | tranny surprise sophy | tranny surprise tanya | tranny surprise tiffany

  19. Hmm, now that was an interesting post! thanks for sharing. Well, I wish you good luck with your site and keep up the good work!

  20. I just read this quote today and I think it’s awesome:It is by universal misunderstanding that all agree. For if, by ill luck, people understood each other, they would never agree.Charles BaudelaireJust thought I’d share.Mike

  21. Gaurav Goel says:

    Using Proxy for small projects might be a longer path but it still helps. We look for objects as usual and nothing new to determine where it goes next.Gaurav Goel

  22. Angelo Zanellato says:

    my name is Zanellato AngeloI have a problem with FLASH 2004, with 120 F/ s loses all the events, I ask a counselthank you AZ.