robotlegs / robotlegs-framework

An ActionScript 3 application framework for Flash and Flex
https://robotlegs.tenderapp.com/
MIT License
967 stars 261 forks source link

Losing event type using modularity to relay between child and parent contexts #152

Closed pixels4nickels closed 11 years ago

pixels4nickels commented 11 years ago

Hey guys,

I was messing with a simple parent/child context example, where the parent has an event mapped to a command, then a child(with it's own context) dispatches the event.

The parent is catching the event and attempting to inject the command event property when it fails. Here is a simple example to illustrate what I am experiencing.

https://github.com/pixels4nickels/ParentChildContext

Line 84 of the CommandExecutor fails due to not being able to satisfy injections within the command: command = _injector.getOrCreateNewInstance(commandClass);

In my example the command injection property type StateEvent is getting turned into a Event. I see in the stack trace that there are 2 dispatches where the event is handed from 1 to the other. These are from the EventRelay listening and dispatching. The source dispatcher dispatches as a StateEvent, then the destination dispatches as a Flash Event. So when the command trigger tries to map the classes and values, the class is a StateEvent but the value is a flash.event.Event

pixels4nickels commented 11 years ago

After further poking I realized the the issue is easily seen in the EventCommandTrigger in the eventHandler method.

If I map my command omitting the event class type: commandMap.map(StateEvent.STATE_A).toCommand(ChangeStateCommand);

the eventHandler gets a flash.events::Event as the eventConstructor, and no _eventClass (since it was not declared in config). This causes the command to fail to find the required StateEvent that was dispatched by the ChildViewMediator. This method does not fail silently (applyInjectionPoints error)

If I map my command using the event class type: commandMap.map(StateEvent.STATE_A, StateEvent).toCommand(ChangeStateCommand);

the eventHandler gets a flash.events::Event as the eventConstructor, and the _eventClass is a StateEvent class reference. But since we got the flash.events::Event as the type, we still fail to inject the event into the command. This method fails silently.

The strangest thing about it all - my flash.events::Event that the eventHandler gets, has a type set to the StateEvent class that was originally dispatched!

In the end I think that the EventRelay::addListener my be the root of it.

private function addListener(type:String):void { _source.addEventListener(type, _destination.dispatchEvent); } Is this down casting the StateEvent to an Event during re-dispatch? My stack trace show it going out of 1 dispatcher as a StateEvent and out of the destination as a flash.events.Event.

It is interesting that it knows enough, by looking at the type string, to look up the proper command. Unfortunately the way the eventConstructor property is satisfied, we end with the wrong event type.

creynders commented 11 years ago

Not entirely sure this will fix it, but I think this happens since StateEvent has no clone method.

We also changed the way mapped events are injected into commands. If you explicitly declare the event as in

commandMap.map(StateEvent.STATE_A, StateEvent).toCommand(ChangeStateCommand);

it will be injected as a StateEvent and if you omit the concrete event type:

commandMap.map(StateEvent.STATE_A).toCommand(ChangeStateCommand);

it will be injected as an Event.

pixels4nickels commented 11 years ago

I feel so silly.. I forgot the clone, thanks!!! Well at least I gave myself a good tour of the new command mapping work!