Different custom events with same types problem.
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.
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
1 Posted by Jason Dias on 10 Oct, 2010 10:19 AM
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 Posted by Flex Incubator on 10 Oct, 2010 10:26 AM
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
3 Posted by Stray on 10 Oct, 2010 10:33 AM
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.
Support Staff 4 Posted by Shaun Smith on 10 Oct, 2010 10:34 AM
Hi Ilya,
How are you mapping your commands? This, for example, will cause issues (as Jason pointed out):
The commandMap allows you to pass a concrete event class through for stronger typing.
Likewise with the eventMap.
Even though the
eventClass
parameter is optional in both cases, I would recommend always using it.5 Posted by Stray on 10 Oct, 2010 10:38 AM
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
Support Staff 6 Posted by Shaun Smith on 10 Oct, 2010 10:42 AM
Flash event dispatching is not type-safe. Listeners are always bound by plain strings, for example:
Is identical to:
7 Posted by Flex Incubator on 10 Oct, 2010 10:43 AM
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 Posted by Flex Incubator on 10 Oct, 2010 10:44 AM
Understood.
9 Posted by Flex Incubator on 10 Oct, 2010 10:46 AM
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?
Support Staff 10 Posted by Shaun Smith on 10 Oct, 2010 10:50 AM
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 Posted by Flex Incubator on 10 Oct, 2010 10:52 AM
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...Support Staff 12 Posted by Shaun Smith on 10 Oct, 2010 10:53 AM
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.
Support Staff 13 Posted by Shaun Smith on 10 Oct, 2010 10:54 AM
Something is still wrong if the error is occurring. Please check how you are mapping listeners in your mediators.
14 Posted by Flex Incubator on 10 Oct, 2010 10:56 AM
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 nowSupport Staff 15 Posted by Shaun Smith on 10 Oct, 2010 11:03 AM
Yes, that's exactly it!
16 Posted by Flex Incubator on 10 Oct, 2010 11:04 AM
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 Posted by Flex Incubator on 10 Oct, 2010 11:12 AM
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.
Support Staff 18 Posted by Ondina D.F. on 10 Oct, 2010 11:13 AM
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 Posted by Flex Incubator on 10 Oct, 2010 11:15 AM
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
Flex Incubator closed this discussion on 10 Oct, 2010 11:15 AM.
Shaun Smith re-opened this discussion on 10 Oct, 2010 11:17 AM
Support Staff 20 Posted by Shaun Smith on 10 Oct, 2010 11:17 AM
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.
21 Posted by Flex Incubator on 10 Oct, 2010 12:38 PM
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 mystarup()
I dispatchContextEvent.STARTUP
at the end, so after all mapping are done (and this event triggers all subsequent chain). This means thatonRegister()
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
Support Staff 22 Posted by Shaun Smith on 10 Oct, 2010 12:55 PM
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.
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?
23 Posted by Flex Incubator on 10 Oct, 2010 01:04 PM
Yes, Shaun. I understand now. Thanks a lot for help ! :)
Ilya
Support Staff 24 Posted by Shaun Smith on 10 Oct, 2010 01:08 PM
Groovy! :-)
Shaun Smith closed this discussion on 10 Oct, 2010 01:08 PM.