View Full Version : Extending Accordion
flexKnight
05-23-2008, 10:41 AM
Hi, I have a simple requirement. I have an accordion. My requirement is such that whenever i click on the header, the accordion does not change instantly. Instead it gives an alert "do you with to navigate to new node" and at a click on "Yes" i should be navigated to new node. Click on "No" keeps me back to the same state.
I have tried to use preventDefault() on click event, however, it does not work as it is not cancel able. http://www.actionscript.org/forums/images/smilies/confused.gif
:confused: If it is programatically not feasible, would love to have a workaround.
Any help is welcome.
Thanks in Advance.
kahuja
05-23-2008, 01:47 PM
You can overload the Accordion's HeaderRenderer and then do whatever you want to do. You will have to implement the mx.core.IDataRenderer
flexKnight
05-26-2008, 08:14 AM
Hi,
thanks for your reply. But, pardon me for being so stupid. can you give an example to elaborate the situation. I am somewht new to flex. thanks
kahuja
07-31-2008, 04:44 AM
Hi,
thanks for your reply. But, pardon me for being so stupid. can you give an example to elaborate the situation. I am somewht new to flex. thanks
Sorry for replying so late - i was kind of stuck into something else. What I meant was that Accordion has been compiled as a single control that has 2 distinct areas i.e. Header and Body. By default, the header has certain functionality which is out of the box. This can be overridden by writing our own implementation which extends a specific interface. Once you do that you have the capability of showing whatever you want to show and also how ever you want to handle the events.
More specifically, in your case, you can very well capture the click even in the renderer and then not call the default implementation i.e. to open the node. Instead open an alert and then do as user suggests.
I know this is all theory and you may be looking for a practical situation. Where I stand, i do not see myself getting into coding for another 2-3 weeks. I would be able to get back to hometown where I have my development environment all setup. It is then, i can provide some code files that would be helpful.
noisey
07-31-2008, 06:36 PM
Someone has to have a quick solution for this?
Sly_cardinal
08-01-2008, 03:24 AM
A fair amount of the Accoridon behaviour is hidden in private functions which means that extending the functionality of the component isn't as straightforward as you might hope.
Luckily we do have access to the Accordion headers through the getHeaderAt function. If you look at the source code for the Accordion class you'll see that the containers set as children of the Accodion instance are actually held inside the 'header' buttons. The headers are the components that listen for the click event and set the visible child.
The header click handler function is private so we can't just override the handler implementation. Instead we will add our own event listener to each header and implement the functionality from there.
This is our click handler:
private function headerClickHandler(event:MouseEvent):void
{
if (!ignoreClick)
{
ignoreClick = true;
event.stopImmediatePropagation();
clickedHeader = Button(event.currentTarget);
clickEvent = event.clone();
// Display the alert.
var alert:Alert = Alert.show("Do you wish to continue?", "Navigate Away?",
Alert.YES | Alert.NO, this, alertHandler);
}
}
The general idea is that we prevent the Accordion from receiving the event (by calling stopImmediatePropogation()), display the Alert asking if the user wants to change the accordion.
If the user wants to navigate then we dispatch the click event from the button again and let the accordion handle the event as it normally does.
private function alertHandler(event:CloseEvent):void
{
if (event.detail == Alert.YES)
{
// Continue with accordian navigation.
clickedHeader.dispatchEvent(clickEvent);
}
else
{
// No - do nothing.
}
ignoreClick = false;
clickedHeader = null;
clickEvent = null;
}
We use the ignoreClick property to avoid handling the second click event that we dispatch from the button.
If that all doesn't make much sense don't worry, the source code attached (including an MXML example using composition) and that should make things clearer.
noisey
08-01-2008, 12:12 PM
Thanks Sly!!! Now I just need to figure out how to adapt this to work in flash7/as2.0 with the accordion component. :(
Sly_cardinal
08-03-2008, 04:21 AM
Thanks Sly!!! Now I just need to figure out how to adapt this to work in flash7/as2.0 with the accordion component. :(
Ah, that's a bit different...
I've had a look through the Actionscript 2 Accordion class and we need to deal with this a bit differently. Instead of overriding the header click events we'll override the Accordion function that is called when a header is clicked - the 'headerPress' function.
(If you're curious the Accordion class files are located at: \[flash install location]\en\First Run\Classes\mx\containers)
First of all we'll listen for the accordion instance's 'load' event -we then redefine the 'headerPress' function so we can display the Alert. In the Alert event handler we can then call the original 'headerPress' function to change the selected Accordion child.
import mx.containers.Accordion;
import mx.controls.SimpleButton;
import mx.utils.Delegate;
import mx.controls.Alert;
function loadHandler(eventObject:Object):Void
{
var target:Accordion = eventObject.target;
var accChildren:Number = target.numChildren;
// This will hold information about the Accordion with which we are interacting.
var handlerObject:Object = new Object();
handlerObject.eventTarget = target; // The accordion instance.
handlerObject.selectedHeader = null;
handlerObject.alertHandler = Delegate.create(handlerObject, alertHandler);
// Keep a copy of the original 'headerPress' function.
handlerObject.defaultHeaderPress = Delegate.create(target, target.headerPress);
// Redefine the header press function.
target.headerPress = Delegate.create(handlerObject, headerPressHandler);
}
// This is executed in the scope of the 'handlerObejct' above.
function headerPressHandler(header:SimpleButton):Void
{
var selectedContent:Object = header["content_mc"];
var currentContent:Object = this.eventTarget.selectedChild;
// Only display the alert if we are attempting to view a different child.
if (selectedContent != currentContent)
{
// Keep a reference to the accordion header.
this.selectedHeader = header;
Alert.show("Continue with navigation?", "Navigate Away?",
Alert.OK | Alert.CANCEL, null, this.alertHandler);
}
}
// This is executed in the scope of the 'handlerObejct' above.
function alertHandler(eventObject:Object):Void
{
if (eventObject.detail == Alert.OK)
{
// Continue with navigation.
this.defaultHeaderPress(this.selectedHeader);
}
this.selectedHeader = null;
}
acc.addEventListener("load", Delegate.create(this, loadHandler));
Note that I am using the Delegate class to control the scope of function execution.
Source and example attached.
noisey
08-04-2008, 06:54 PM
awesome work! How would you listen for a rollover in the AS2 example?... Instead of the alert popping up on a click, it would pop up on a rollover?
Sly_cardinal
08-05-2008, 12:49 AM
It should be possible, although I think it will require hacking the Accordion component files a little bit.
I'll have a look into it later - just a bit busy at the moment.
noisey
08-05-2008, 01:05 AM
Here is what I came up with, it see's the rollover and triggers a trace, now I just tried to copy and paste the string from the alert function that actually triggers, but I think I am missing something or not seeing something.
import mx.containers.accordionclasses.AccordionHeader;
import mx.containers.Accordion;
import mx.controls.SimpleButton;
import mx.utils.Delegate;
function loadHandler(eventObject:Object):Void
{
// This will hold information about the Accordion with which we are interacting.
var handlerObject:Object = new Object();
var target:Accordion = eventObject.target;
var accChildren:Number = target.numChildren;
//target.headerPress = Delegate.create(this, headerPressHandler);
handlerObject.eventTarget = target;
handlerObject.selectedHeader = null;
handlerObject.defaultHeaderPress = Delegate.create(target, target.headerPress);
handlerObject.onRollOverPress = Delegate.create(target, target.onRollOver);
// Redefine the header press function.
target.onRollOver = Delegate.create(handlerObject, onRollOverPressHandler);
}
// This is executed in the scope of the 'handlerObejct' above.
function onRollOverPressHandler(header:SimpleButton):Void
{
var selectedContent:Object = header["content_mc"];
var currentContent:Object = this.eventTarget.selectedChild;
// Only display the alert if we are attempting to view a different child.
if (selectedContent != currentContent)
{
// Keep a reference to the accordion header.
trace ("ROLLEDOVER")
this.defaultHeaderPress(this.selectedHeader);
}
}
acc.addEventListener("load", Delegate.create(this, loadHandler));
attached is the fla
|
vBulletin® v3.8.5, Copyright ©2000-2012, Jelsoft Enterprises Ltd.