Different custom events with same types problem.

Flex Incubator's Avatar

Flex Incubator

10 Oct, 2010 10:16 AM

Hello.
I am not sure whether this is a problem in Robotlegs, Flex or just my code. So, here is what I have:
1)Two custom events EventA and EventB. Both events has similar type EventA.READY and EventB.READY
2)Here is the workflow of my app: the app starts>CommandA is triggered>data is loaded>ModelA is updated>ModelA dispatch EventA.READY>CommandB is triggered>data is loaded>ModelB is updated>ModelB dispatch EventB.READY>view components, which are listening for EventB.READY update their states.

Ok, and here is the problem. When I run the app I've got a Type Coercion failed: cannot convert EventA into EventB. This particular error occur when ModelA dispatches EventA.READY. Once I change "ready" type of EventA to anything else, the error disappears.
Plus, even when I have an error, but hit Dismiss all button in error popup of flash player, my view components are updated as they should (so this error has no impact on result). Could somebody clarify for me what's going on and what I did wrong.

Ilya.

  1. 1 Posted by Jason Dias on 10 Oct, 2010 10:19 AM

    Jason Dias's Avatar

    Remember Event.READY is still of type String, so the Strings need to be unique. One way to do this is to put the class name in the value as well:

    EventA
    public static const READY:String = "EventA.ready";

    EventB
    public static const READY:String = "EventB.ready";

  2. 2 Posted by Flex Incubator on 10 Oct, 2010 10:26 AM

    Flex Incubator's Avatar

    Well, yes, they are strings, but these string belongs to different classes. I thought, when event is dispatched, the new instance of some particular event is created, and not only its type? right? So, still does not understand why this error occurs. Actually, to clarify more, the exact place where this error comes from is

    at org.robotlegs.base::EventMap/routeEventToListener()[/Users/shaun/Documents/Development/Workspaces/GanymedeFB4/robotlegs-framework/src/org/robotlegs/base/EventMap.as:181] at Function/()[/Users/shaun/Documents/Development/Workspaces/GanymedeFB4/robotlegs-framework/src/org/robotlegs/base/EventMap.as:107] at flash.events::EventDispatcher/dispatchEventFunction() at flash.events::EventDispatcher/dispatchEvent() at org.robotlegs.mvcs::Actor/dispatch()[/Users/shaun/Documents/Development/Workspaces/GanymedeFB4/robotlegs-framework/src/org/robotlegs/mvcs/Actor.as:98]

  3. 3 Posted by Stray on 10 Oct, 2010 10:33 AM

    Stray's Avatar

    Agreed - I do this - including the event name, sometimes even the full package and event name, as well as the string.

    However, robotlegs also allows you to map commands based on event class type as well as the event string.

    commandMap.mapEvent(eventType:String, commandClass:Class, eventClass:Class = null, oneshot:Boolean = false)

    And events where the event type is used as well as the event string:

    eventMap.mapListener(dispatcher:IEventDispatcher, type:String, listener:Function, eventClass:Class = null, useCapture:Boolean = false, priority:int = 0, useWeakReference:Boolean = true)

    So - I always go for both for the command map.

    The shorthand, addContextListener / addViewListener both also allow you to pass the eventClass immediately after the listener function to ensure that you don't get the error you're seeing.

    The reason I do both is that if I want to use the events outside of robotlegs, having unique strings still gives me the protection, and specifying the event in my robotlegs code clearly communicates my intent.

  4. Support Staff 4 Posted by Shaun Smith on 10 Oct, 2010 10:34 AM

    Shaun Smith's Avatar

    Hi Ilya,

    How are you mapping your commands? This, for example, will cause issues (as Jason pointed out):

    commandMap.mapEvent( EventA.READY, CommandA );
    commandMap.mapEvent( EventB.READY, CommandB );
    eventDispatcher.dispatchEvent( new EventA( EventA.READY ) );
    

    The commandMap allows you to pass a concrete event class through for stronger typing.

    commandMap.mapEvent( EventA.READY, CommandA, EventA );
    commandMap.mapEvent( EventB.READY, CommandB, EventB );
    

    Likewise with the eventMap.

    Even though the eventClass parameter is optional in both cases, I would recommend always using it.

  5. 5 Posted by Stray on 10 Oct, 2010 10:38 AM

    Stray's Avatar

    To clarify (you'll see my other reply in the meantime) - a weakness of the flash event system is that it relies on strings for event classification - you bind to a string, and not to an instance of an event. When you add a listener in flash to Event.COMPLETE, you're listening ONLY for the string that is the event type "complete". If that same string is also in SomeOtherEvent.COMPLETE then you'll get false positives.

    Robotlegs improves on this by allowing you to actually bind to an event class as well as a string, by using the extra parameters in my first reply - which I'm guessing you're not using.

    The reason you see the error is that the robotlegs eventMap does a clone/redispatch action which if you were binding directly to the event in flash you wouldn't see. While you're obviously feeling frustrated by the error, the noisy fail at least alerts you to the problem. In simple flash you would just have thing happening when you didn't expect them to, or missing values, and you'd be stuck with odd behaviour and null errors and not much idea what had gone wrong.

    Sometimes errors are helpful :)

    Stray

  6. Support Staff 6 Posted by Shaun Smith on 10 Oct, 2010 10:42 AM

    Shaun Smith's Avatar

    Well, yes, they are strings, but these string belongs to different classes. I thought, when event is dispatched, the new instance of some particular event is created, and not only its type? right? So, still does not understand why this error occurs.

    Flash event dispatching is not type-safe. Listeners are always bound by plain strings, for example:

    sprite.addEventListener(MouseEvent.CLICK, handler);
    

    Is identical to:

    sprite.addEventListener("click", handler);
    
  7. 7 Posted by Flex Incubator on 10 Oct, 2010 10:43 AM

    Flex Incubator's Avatar

    OK, here is the code snippet from my context class

    commandMap.mapEvent(ContextEvent.STARTUP, CommandA, ContextEvent, true); commandMap.mapEvent(EventA.READY, CommandB, EventA, true);

    EventB does not mapped to command, because it triggers the change of view components and not some command. So, I do have passed event class in mapEvent(). Maybe I still missed something? Should I map EventB somewhere?

  8. 8 Posted by Flex Incubator on 10 Oct, 2010 10:44 AM

    Flex Incubator's Avatar

    Flash event dispatching is not type-safe. Listeners are always bound by plain strings

    Understood.

  9. 9 Posted by Flex Incubator on 10 Oct, 2010 10:46 AM

    Flex Incubator's Avatar

    So, just to summarize - if I am creating custom events, I should never use the same types (strings) even if similar event type is in absolutely different event class? Right?

  10. Support Staff 10 Posted by Shaun Smith on 10 Oct, 2010 10:50 AM

    Shaun Smith's Avatar

    Maybe I still missed something? Should I map EventB somewhere?

    Are you still getting the error? The error was coming from an eventMap, so it looks like the problem originates in a mediator. Are you passing the event class through to your eventMap in you mediators?

  11. 11 Posted by Flex Incubator on 10 Oct, 2010 10:52 AM

    Flex Incubator's Avatar

    Well, then what are the real benefit of specifying concrete Event class in commandMap.mapEvent(). Because even though I have specified it, the error occurs (well, I know now how to avoid it, by unique event types), but still wonder...

  12. Support Staff 12 Posted by Shaun Smith on 10 Oct, 2010 10:53 AM

    Shaun Smith's Avatar

    if I am creating custom events, I should never use the same types (strings) even if similar event type is in absolutely different event class? Right?

    As Stray pointed out, Robotlegs can distinguish between different events with the same type (string), but outside of Robotlegs that is not the case, so she does both: ensures that all mappings supply the event class, and that no event type strings clash.

  13. Support Staff 13 Posted by Shaun Smith on 10 Oct, 2010 10:54 AM

    Shaun Smith's Avatar

    Well, then what are the real benefit of specifying concrete Event class in commandMap.mapEvent(). Because even though I have specified it, the error occurs (well, I know now how to avoid it, by unique event types), but still wonder...

    Something is still wrong if the error is occurring. Please check how you are mapping listeners in your mediators.

  14. 14 Posted by Flex Incubator on 10 Oct, 2010 10:56 AM

    Flex Incubator's Avatar

    Are you still getting the error? The error was coming from an eventMap, so it looks like the problem originates in a mediator. Are you passing the event class through to your eventMap in you mediators?

    Well, the error occurs long before the mediators catch EventB. Because the error occurs when ModelA dispatch EventA. Then goes CommandB>ModelB>EventB and only now mediators catch EventB. Or do you ask whether I specify concrete event class in addContextListener() method in mediators? No, I did not, I will try now

  15. Support Staff 15 Posted by Shaun Smith on 10 Oct, 2010 11:03 AM

    Shaun Smith's Avatar

    Or do you ask whether I specify concrete event class in addContextListener() method in mediators? No, I did not, I will try now

    Yes, that's exactly it!

  16. 16 Posted by Flex Incubator on 10 Oct, 2010 11:04 AM

    Flex Incubator's Avatar

    OK, I have specified concrete event class in mediators like this
    addContextListener(EventB.READY, handler, EventB);

    and the error has gone. Though it a little bit weird for me (weird just because I can not understand why specifying concrete event class in that piece of code which is executed long after the error actually occur, do the trick). I guess I need to drill down into theory :)

    Anyway, thanks everybody for help. I definitely know more now :)

    Ilya

  17. 17 Posted by Flex Incubator on 10 Oct, 2010 11:12 AM

    Flex Incubator's Avatar

    can not set resolved status for this post for some reasons. Do not know why, it redirects me to new page where I can open new post.

  18. Support Staff 18 Posted by Ondina D.F. on 10 Oct, 2010 11:13 AM

    Ondina D.F.'s Avatar

    Just to add to the possible causes already mentioned:

    Could it be that you listen for that custom event like this:
    eventMap.mapListener(eventDispatcher, EventB.READY, onEventBReady);

    and then you have
    protected function onEventBReady(event:Event):void

    instead of

    protected function onEventBReady(event: EventB):void

    This would also throw an Error: Type Coercion failed

    Ondina

  19. 19 Posted by Flex Incubator on 10 Oct, 2010 11:15 AM

    Flex Incubator's Avatar

    Hello, Ondina.
    No, I have specified custom event class in event handler. So, the reason was definitely in specifying concrete event class in addContextListener(EventB.READY, handler, EventB);.

    Ilya

  20. Flex Incubator closed this discussion on 10 Oct, 2010 11:15 AM.

  21. Shaun Smith re-opened this discussion on 10 Oct, 2010 11:17 AM

  22. Support Staff 20 Posted by Shaun Smith on 10 Oct, 2010 11:17 AM

    Shaun Smith's Avatar

    Though it a little bit weird for me (weird just because I can not understand why specifying concrete event class in that piece of code which is executed long after the error actually occur, do the trick).

    Because it was triggering as soon as you dispatched EventA.READY (not "long after" as you thought).

    It's quite important to understand why this was happening. If it's still unclear to you, let's keep chatting until it makes sense.

  23. 21 Posted by Flex Incubator on 10 Oct, 2010 12:38 PM

    Flex Incubator's Avatar

    Shaun, It's much appreciated that you want to clarify everything.

    First of all I am not sure I understand why you say that "it was triggering as soon as you dispatched EventA.READY". I have put some trace() code, and figured out that this error occurs before EventB is dispatched.

    What I really do not understand is the mechanism of this error, what is behind the curtain. According to the error, EventA tries to be EventB. But why? EventB was not even dispatched when error occurs. Does the understanding of my problem lays in understanding what is EventMap?

    The only thing that I think may have some impact on this situation is the code in starup() of the context, where I map view component to its mediator. In my starup() I dispatch ContextEvent.STARTUP at the end, so after all mapping are done (and this event triggers all subsequent chain). This means that onRegister() method of my mediator runs before EventA is dispatched, and this method maps EventB (but without concrete event class). Does mapping of the EventB means that some reference to this event occurs? Not sure if all my last sentences make sense. This is just my thoughts of possible reasons (more precisely of possible entry point of the problem).

    Ilya

  24. Support Staff 22 Posted by Shaun Smith on 10 Oct, 2010 12:55 PM

    Shaun Smith's Avatar

    Hi Ilya,

    The problem was that your mediator was listening for EventB.READY (which evaluates to "ready"), so when you dispatched EventA.READY (which also evaluates to "ready") it caught the event and exploded because the listener function was expecting an event of type EventB.

    I have put some trace() code, and figured out that this error occurs before EventB is dispatched.

    Exactly, the error occurred as soon as you dispatched EventA.READY - because you didn't specify the concrete event class, the mediator's eventMap was responding to any event with the string type "ready", no matter what class it was.

    By specifying the event class, the eventMap then filters out events (like instances of EventA) that don't match the specified class.

    Does that help explain it?

  25. 23 Posted by Flex Incubator on 10 Oct, 2010 01:04 PM

    Flex Incubator's Avatar

    Yes, Shaun. I understand now. Thanks a lot for help ! :)

    Ilya

  26. Support Staff 24 Posted by Shaun Smith on 10 Oct, 2010 01:08 PM

    Shaun Smith's Avatar

    Groovy! :-)

  27. Shaun Smith closed this discussion on 10 Oct, 2010 01:08 PM.

Comments are currently closed for this discussion. You can start a new one.

Keyboard shortcuts

Generic

? Show this help
ESC Blurs the current field

Comment Form

r Focus the comment reply box
^ + ↩ Submit the comment

You can use Command ⌘ instead of Control ^ on Mac