I have been immersed in Flex 4 lately and had this issue come up. Â It seems like it might be fairly easy to run into and isn’t entirely obvious at first so I’ll share. Â I had a custom component that included buttons that weren’t registering click events.
Here’s the scenario. Â I created a custom component that contained a background rectangle for highlighting, a label to display the name of the item, a toggle button for expanding the item and a button for editing the item. Â I won’t get into the specifics of what this component is for, but just stick to the high level concept.
[ [expandBtn:ToggleButton] [labelDisplay:Label] [editBtn:Button] ]
The component had a number of states:
[SkinState("up")] [SkinState("over")] [SkinState("down")] [SkinState("upAndSelected")] [SkinState("overAndSelected")] [SkinState("downAndSelected")]
This is similar to the ToggleButton component in the SDK but didn’t need the disabled state. Â I created mouseEvent handlers to take the rollOver, rollOut, mouseDown, mouseUp and click events so I could handle them appropriately, setting properties for the getCurrentSkinState() method to use and setting invalidateSkinState() after changing the properties.
In the components up state, I wanted just the label to show and then when the user hovers over the component, the expand and edit buttons show. Â Using states, this is simple enough to accomplish in the skin for the component:
<s:states> <s:State name="up" /> <s:State name="over" stateGroups="overStates" /> <s:State name="down" stateGroups="downStates" /> <s:State name="upAndSelected" stateGroups="selectedStates" /> <s:State name="overAndSelected" stateGroups="overStates, selectedStates" /> <s:State name="downAndSelected" stateGroups="downStates, selectedStates" /> </s:states> ...<s:ToggleButton id="expandBtn" includeIn="overStates" .../><s:Label id="labelDisplay" ... /><s:Button id="editBtn" includeIn="overStates" .../>
The ellipses indicate additional code that is irrelevant.
I added the click handlers for the buttons in the custom component so I could capture the clicks and dispatch my own custom event.
So this starts out looking fine. Â The buttons show up when the mouse is hovered. Â Great. Â I click on the edit button and… nothing. Â The click handler is never called. Â Do you see why?
Hint: Because events like clicks travel the displayList, the surrounding component will react to the clicks of the buttons inside it too.
Ok, here’s the chain of events:
- The user presses the mouse button down over the edit button.
- The edit button gets the mouseDown and enters it’s down state (if it has one).
- The surrounding component gets the mouseDown and changes it’s skin state to the down state.
- The edit button is not included in the down state, so it is removed.
- The user releases the mouse button.
- The surrounding component gets the mouseUp and returns to the over state.
- The edit button is included in the over state so it appears again.
Since the edit button wasn’t included in the down state, it never had a chance to react to a click event. Â Click events occur when the user presses and releases the mouse button over a component and the edit button was not around for that whole chain of events.
Solution: Add the buttons into the downStates so they exist during the entire click action. Â Problem solved.