Programmatically changing a Flex Accordion container’s selected index

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.

15 thoughts on “Programmatically changing a Flex Accordion container’s selected index

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

  2. 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

  3. 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

  4. 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?

  5. 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

  6. 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

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

    acc.getHeaderAt(0).enabled = false;
    

    Peter

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

    OMG TY TY TY

    – Nick

  9. 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

  10. 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);
    }
    
  11. 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);
    }
    

Comments are closed.