it is possible to automatically wire up events in the view to handlers
in the controller by using the [ViewHandler] metadata tag. Using this
tag wires up a function in the controller to handle a particular event
from the view itself. Therefore the event.currentTarget in the handler
will always be component.view. Ben suggested in the now closed
discussion
http://groups.google.com/group/openflux/browse_thread/thread/46bc71ad0377bc15/5439efa0cd872749?lnk=gst&q=target#5439efa0cd872749
that if you were interested in a click event on a particular child of
view, rather than the view as a whole, you could look at
event.target.
However looking at the event.target doesn't always work, because if
the
sub-control that you're interested in has subcomponents, one of those
might be the event.target. Therefore need to check if the control is
either the event.target, or one of it's direct ancestors. I've written
a class which achieves this:
package at.newbe.view.utils
{
import flash.display.DisplayObject;
import flash.events.MouseEvent;
/**
* ...
* @author Frederick G Fisher IV
* @copy Newbe.at
*/
public class ViewHandlerUtil
{
public static function isDescendant
(target:DisplayObject,
ancestor:DisplayObject, context:DisplayObject=null):Boolean {
//what's the top level element in the search?
var root:DisplayObject = (context) ? context :
target.root;
if (!root) return false
//search up the displayobject hierarchy
var current:DisplayObject = target;
while (current) {
if (current == ancestor) return true;
else if (current == root) break;
current = current.parent;
}
return false;
}
public static function executeHandler(event:MouseEvent,
handlers:Array, context:DisplayObject=null,
stopProp:Boolean=true):void {
var target:DisplayObject = event.target as
DisplayObject;
//go through the instructions of what handler
for what ancestor, do
the appropriate handler
for each (var handler:Array in handlers) {
var ancestor:DisplayObject = handler[0]
as DisplayObject;
if (isDescendant(target, ancestor,
context)) {
var handlerFunction:Function =
handler[1] as Function;
handlerFunction(event);
if (stopProp)
event.stopPropagation();
break;
}
}
}
}
}
you use it like this:
[ViewHandler(event="mouseUp", handler="mouseUpHandler")] //at top of
class
[ViewContract] public var control:ControlType;
metadata function mouseUpHandler(event:MouseEvent):void {
ViewHandlerUtil.executeHandler(event,
[[control, controlHandler]],
component.view as DisplayObject);
}
private function controlHandler(e:MouseEvent) { trace("clicked the
control"); }
That is to say:
1. metadata a ViewHandler for whatever kind of mouse event you're
interested in
2. make a view contract variable that will either reference the
control you want directly, or type component.view to a custom view
that has controls of same type but different ids
3. in the ViewHandler function, call ViewHandlerUtil.executeHandler
(event, [control/handler mappings], typically component.view as
DisplayObject)
4. implement the handlers from the control/handler mappings array
This is what it might look like with a custom view with buttons id of
button1, button2, button3...
(n.b please correct if you can't use ViewContract to reference the
view itself, if not then reference component.view as CustomViewType in
the mouseUpHandler)
[ViewContract] public var customView:CustomViewType;
metadata function mouseUpHandler(event:MouseEvent):void {
ViewHandlerUtil.executeHandler(event,
[[customView.button1,
button1Handler],[customView.button2, button2Handler],
[customView.button3, button3Handler]], component.view as
DisplayObject);
}
private function button1Handler(e:MouseEvent) { trace("clicked
button1"); }
private function button2Handler(e:MouseEvent) { trace("clicked
button2"); }
private function button3Handler(e:MouseEvent) { trace("clicked
button3"); }
This works in a kind of roundabout way compared to the direct way, of
adding an id field to the ViewHandler directive, but it works directly
without changing anything already in OpenFlux so you can use it today.
I'm interested in the logic of not doing haivng id in the ViewHandler
directive, perhaps to force events to be dealt with 'centrally' in the
controller? or to make it awkward and encourage controls to deal with
their own events?
by the way, any help from anyone on my issues with lists and setting
default components sizes would be much appreciated :-D
peace and love xx