Programmatically changing a Flex Accordion container’s selected index

by Peter deHaan on September 17, 2007

in Accordion

The following example shows how you can change the currently selected child in an Accordion container using ActionScript by setting the accordion’s selectedIndex property.

Full code after the jump.

View MXML

<?xml version="1.0" encoding="utf-8"?>
<!-- http://blog.flexexamples.com/2007/09/17/programmatically-changing-a-flex-accordion-containers-selected-index/ -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
        layout="vertical"
        verticalAlign="middle"
        backgroundColor="white"
        creationComplete="init();">

    <mx:Script>
        <![CDATA[
            private function init():void {
                slider.maximum = accordion.numChildren -1;
                slider.labels = [0, slider.maximum];
            }

            private function dataTipFunc(item:Object):String {
                return "selectedIndex = " + item.toString();
            }
        ]]>
    </mx:Script>

    <mx:ApplicationControlBar dock="true">
        <mx:Label text="selectedIndex:" />
        <mx:HSlider id="slider"
                minimum="0"
                liveDragging="true"
                snapInterval="1"
                tickInterval="1"
                change="accordion.selectedIndex = event.value;"
                dataTipFormatFunction="dataTipFunc"
                dataTipPlacement="bottom" />
    </mx:ApplicationControlBar>

    <mx:Accordion id="accordion"
            historyManagementEnabled="false"
            width="100%"
            height="100%"
            change="slider.value = event.newIndex;">
        <mx:VBox label="One" />
        <mx:VBox label="Two" />
        <mx:VBox label="Three" />
        <mx:VBox label="Four" />
        <mx:VBox label="Five" />
    </mx:Accordion>

</mx:Application>

View source is enabled in the following example.

{ 14 comments… read them below or add one }

1 Czar September 18, 2007 at 4:10 am

It would be couuld to have live examples again…

Reply

2 peterd September 18, 2007 at 9:13 am

Sorry about that, I’ll try and upload and embed the SWFs tonight after work.

Peter

Reply

3 max February 21, 2008 at 2:15 am

I need to set accordion into state without selected items (selectedIndex = – 1 or something doesn’t work)
is there any solutions for this& thanks

Reply

4 Rod March 26, 2008 at 10:54 am

Max,

I’m guessing you would something like:

acc.selectedIndex = (acc.selectedIndex - 1);

——————

Peter,
Is there a way to cancel a change event or disable a header? I have 3 containers and do not want the users to leave the first container until a value has been filled out. i tried adding enabled='false' on the other two VBox’s, but the Accordion header doesn’t honor that apparently.

thx.
-r

Reply

5 Rod March 26, 2008 at 11:01 am

Nevermind, I got it working by referencing your getHeaderAt() example:

Accordion.getHeaderAt(1).enabled = false;

I’d like to know if there are others ways to do the same thing, but this will work for me.

regards,
-r

Reply

6 Keith May 9, 2008 at 6:53 am

I am in the same boat as Rod. I want to catch the change event and cancel the accordion slide if certain criteria have not been met. Any ideas?

Reply

7 Nick May 30, 2008 at 10:52 am

Hey Peter,

I’m in the same boat as Rod Keith also lol. Can you possibly do a example on how to disable accordion index’s not allowing the user to click them to bring them up but rather click a continue or submit button in the main accordion index which loads you into the next accordion index?

Please :)

- Nick

Reply

8 peterd May 30, 2008 at 2:11 pm

Keith and Nick,

This should disable all Accordion header mouse clicks and only allow users to change the selected child using the nested Button controls. (I say *should* since I haven’t really tested this):

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
        layout="vertical"
        verticalAlign="middle"
        backgroundColor="white">

    <mx:Accordion id="acc"
            headerRenderer="comps.MyAccHeader"
            width="100%" height="100%">
        <mx:VBox id="v1" label="One">
            <mx:Button label="next" click="acc.selectedChild = v2;" />
        </mx:VBox>
        <mx:VBox id="v2" label="Two">
            <mx:Button label="prev" click="acc.selectedChild = v1;" />
            <mx:Button label="next" click="acc.selectedChild = v3;" />
        </mx:VBox>
        <mx:VBox id="v3" label="Three">
            <mx:Button label="prev" click="acc.selectedChild = v2;" />
            <mx:Button label="next" click="acc.selectedChild = v4;" />
        </mx:VBox>
        <mx:VBox id="v4" label="Four">
            <mx:Button label="prev" click="acc.selectedChild = v3;" />
            <mx:Button label="next" click="acc.selectedChild = v5;" />
        </mx:VBox>
        <mx:VBox id="v5" label="Five">
            <mx:Button label="prev" click="acc.selectedChild = v4;" />
        </mx:VBox>
    </mx:Accordion>

</mx:Application>

comps/MyAccHeader.as

package comps {
    import mx.containers.accordionClasses.AccordionHeader;

    public class MyAccHeader extends AccordionHeader {
        public function MyAccHeader() {
            super();
            mouseEnabled = false;
        }
    }
}

And there may be better ways of doing this, but this was the first thing that came to mind.

Hope that helps,
Peter

Reply

9 peterd May 30, 2008 at 2:52 pm

As for disabling individual Accordion headers, this ActionScript should work:

acc.getHeaderAt(0).enabled = false;

Peter

Reply

10 Nick May 30, 2008 at 4:35 pm

Peter! Thank you sooooooooooooooooo much. Your first reply did the trick EXACTLY what I was looking for!

OMG TY TY TY

- Nick

Reply

11 peterd May 30, 2008 at 5:35 pm

Nick,

Actually, this may be a better way of doing what you want (or, at least I think it is cool):

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
        layout="vertical"
        verticalAlign="middle"
        backgroundColor="white">

    <mx:Accordion id="acc"
            headerRenderer="comps.MyAccHeader"
            width="100%" height="100%">
        <mx:VBox id="v1" label="One">

        </mx:VBox>
        <mx:VBox id="v2" label="Two" enabled="false">

        </mx:VBox>
        <mx:VBox id="v3" label="Three" enabled="false">

        </mx:VBox>
        <mx:VBox id="v4" label="Four">

        </mx:VBox>
        <mx:VBox id="v5" label="Five">

        </mx:VBox>
    </mx:Accordion>

</mx:Application>

comps/MyAccHeader.as

package comps {
    import mx.containers.accordionClasses.AccordionHeader;
    import mx.events.FlexEvent;

    public class MyAccHeader extends AccordionHeader {
        public function MyAccHeader() {
            super();
            addEventListener(FlexEvent.INITIALIZE, accordionHeader_initialize);
        }

        private function accordionHeader_initialize(evt:FlexEvent):void {
            enabled = data.enabled;
        }
    }
}

Now the enabled property on the VBox container should bubble up to the AccordionHeader.

In fact, I think it is SO cool and useful that I may turn it into today’s “official”
example (and that way it will get a nice SWF too).

Happy Flexing!
Peter

Reply

12 peterd May 30, 2008 at 11:43 pm
13 Scooter August 24, 2008 at 7:04 am

After fighting with trying to stop this event to make a user fill in a required vale before moving to another step I found an interesting way to accomplish it:

private function accBuildSteps_test(e:IndexChangedEvent):void {
    // perform validations before allowing step change
    if (e.newIndex > 0) {
        // selection required to move beyond this step
        if (mgrProducts.SelectedFabric == null) {
            accBuildSteps.addEventListener(FlexEvent.UPDATE_COMPLETE, flexUpdateComplete);
            Alert.show("You must select a fabric!");
        }
    }
}

private function flexUpdateComplete(event:Object):void {
    accBuildSteps.selectedIndex = 0;
    accBuildSteps.removeEventListener(FlexEvent.UPDATE_COMPLETE, flexUpdateComplete);
}

Reply

14 Scooter August 24, 2008 at 7:19 am

After fighting with this for quite a while, I came across an interesting way to do this. The code below is not exactly what I am using (my project is a little more complicated than this) but this should give you the basic idea. If the requirement is not met I first store the value of the step to return to and then add an event handler to the accordion for the FlexEvent.UPDATE_COMPLETE event. The handler is called after the event completes. Then we set the accordion selectedIndex back to the stored value we saved earlier and finally we remove the event handler we added. You still see the accordion slide down and then back up and then see the alert. Kind of cool I guess.

private function myAccordion(e:IndexChangedEvent):void {
  // perform validations before allowing step change
  if (e.newIndex > 0) {
    // selection required to move beyond this step
    if (myRequiredItem== null) {
      // save the step to return to
      this.current_step = 0;
      // add the event listener
      myAccordion.addEventListener(FlexEvent.UPDATE_COMPLETE, flexUpdateComplete);
      // show an alert - this won't show until the slide is complete actually
      Alert.show("You must select a fabric!");
    }
  }
}

private function flexUpdateComplete(event:Object):void {
  myAccordion.selectedIndex = this.current_step;
  myAccordion.removeEventListener(FlexEvent.UPDATE_COMPLETE, flexUpdateComplete);
}

Reply

Leave a Comment

Sorry, this blog is terrible at eating HTML comments.
If you're pasting any HTML/XML/MXML code, you need to convert your < characters to &lt; and your > characters to &gt; .

You can use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> <pre lang="" line="" escaped="">

Anti-Spam Protection by WP-SpamFree

Previous post:

Next post: