views:

1953

answers:

3

I have a Flex application where I'm using a Canvas to contain several other components. On that Canvas there is a Button which is used to invoke a particular flow through the system. Clicking anywhere else on the Canvas should cause cause a details pane to appear showing more information about the record represented by this control.

The problem I'm having is that because the button sits inside the Canvas any time the user clicks the Button the click event is fired on both the Button and the Canvas. Is there any way to avoid having the click event fired on the Canvas object if the user clicks on an area covered up by another component?

I've created a simple little test application to demonstrate the problem:

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute">
    <mx:Script>
     <![CDATA[
      private function onCanvasClick(event:Event):void {
       text.text = text.text + "\n" + "Canvas Clicked";
      }

      private function onButtonClick(event:Event):void {
       text.text = text.text + "\n" + "Button Clicked";
      }
     ]]>
    </mx:Script>

    <mx:Canvas x="97" y="91" width="200" height="200" backgroundColor="red" click="onCanvasClick(event)">
     <mx:Button x="67" y="88" label="Button" click="onButtonClick(event)"/>
    </mx:Canvas>
    <mx:Text id="text" x="97" y="330" text="Text" width="200" height="129"/>
</mx:Application>

As it stands when you click the button you will see two entries made in the text box, "Button Clicked" followed by "Canvas Clicked" even though the mouse was clicked only once.

I'd like to find a way that I could avoid having the second entry made such that when I click the Button only the "Button Clicked" entry is made, but if I were to click anywhere else in the Canvas the "Canvas Clicked" entry would still appear.

+4  A: 

The event continues on because event.bubbles is set to true. This means everything in the display heirarchy gets the event. To stop the event from continuing, you call

event.stopImmediatePropagation()
Laplie
It should be noted that this will also prevent any other event listeners *on the current target* from executing. If you want all listeners on the curent target to execute, and just prevent the event from bubbling further, use `event.stopPropagation`.
Hanno Fietz
A: 

I have 2 ideas, first try this:


btn.addEventListener(MouseEvent.Click,function(event:MouseEvent):void{
    event.stopImmediatePropagation();
    ...
});

if that doesn't work, see if you can add the click listener to the canvas and not the button and check the target property on the event object. something like:


btn.addEventListener(MouseEvent.Click,function(event:MouseEvent):void{
    if(event.target == btn){
        ...
    }
    else{
        ...
    }
});

Again, these are some ideas of the top of my head...I'll create a small test app and see if these work...

mmattax
Stopping the event's propagation with the provided methods should always be preferred, it's exactly what they are meant to do. I guess there might well be some scenarios where you'd want to use the second approach, but it's probably very rare.
Hanno Fietz
A: 

Laplie's answer worked like a charm. For those interested the updated code looks like this:

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute">
    <mx:Script>
        <![CDATA[
                private function onCanvasClick(event:Event):void {
                        text.text = text.text + "\n" + "Canvas Clicked";
                }

                private function onButtonClick(event:Event):void {
                        text.text = text.text + "\n" + "Button Clicked";
                        event.stopImmediatePropagation();
                }
        ]]>
    </mx:Script>

    <mx:Canvas x="97" y="91" width="200" height="200" backgroundColor="red" click="onCanvasClick(event)">
        <mx:Button x="67" y="88" label="Button" click="onButtonClick(event)"/>
    </mx:Canvas>
    <mx:Text id="text" x="97" y="330" text="Text" width="200" height="129"/>
</mx:Application>

The only difference is the one additional line in the onButtonClick method.

Mike Deck
Also see my comment on Laplie's answer for the alternative method `event.stopPropagation()`, which is subtly different. (If you only have one listener at the target, they produce the same result.)
Hanno Fietz