Dynamic Tabs in Flex

Posted: December 21, 2006 in Flex

Question: “How do I dynamically add tabs to my TabNavigator?”

Solution: The TabNavigator (and many other controls) support the addChild and addChildTo methods which, allow you to add child controls and components.

Take a look at the sample code segments I’ve posted here:

Down Triangle


1.  <?xml version="1.0" encoding="utf-8"?>
2.  <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
         layout="absolute">
3.  ...
4.  </mx:Application>

Lines 1 through 5 show our standard Flex application Project template.

Down Triangle


1.  <mx:Panel title="TabNavigator Container Example" height="90%" width="90%"
2.  	paddingTop="10" paddingLeft="10" paddingRight="10" paddingBottom="10">

3.  	<mx:TabNavigator id="tn"  width="100%" height="100%"/>

4.  	<mx:Label width="100%" color="blue"
5.  		text="Programmatically add Tab buttons"/>

6.  	<mx:HBox>
7.  		<mx:Button label="Add A Tab" click="addTab()"/>
8.  		<mx:Button label="Remove A Tab" click="removeTab()"/>
9.  	</mx:HBox>

10.  </mx:Panel>

This next code segment describes our interface mxml. Line 1 describes our Panel container with a height and width of 90%. We also specify a padding of 10 pixels from all the borders.

Here on Line 3 we define our TabNavigator. Notice that I am defining a closed tag (no controls defined between an opening and closing TabNavigator tag). This is because we will be defining some ActionScript to add and remove our tab buttons and content.

Line 4 defines a Label that shows the user some instruction.

And finaly on Lines 6 through 9 we define an HBox containing two Buttons. These buttons will execute the functions you will see described below.

Down Triangle


1. <mx:Script>
2.	<![CDATA[
3.		import mx.controls.Button;
4.		import mx.controls.Label;
5.		import mx.containers.VBox;

6.		public var numChild:Number = 0;

7.		public function addTab():void {
8.			var newVBox:VBox = new VBox();
9.			var newLabel:Label = new Label();

10.			numChild = tn.numChildren + 1;

11.			newVBox.label = "Panel " + numChild;

12.			newLabel.text = "TabNavigator container panel " +
                                        numChild;

13.			newVBox.addChild(newLabel);

14.			tn.addChild(newVBox);
15.		}

16.		public function removeTab():void {
17.			if(tn.numChildren > 0){
18.				numChild --;

19.				tn.removeChildAt(numChild);
20.			}
21.		}
22.	]]>
23. </mx:Script>

OK. Now lets get to what we all came here for … the script. Line 3 through 5 import three classes, the Button, the Label, and VBox. Why are we doing this. Later in the code you will see that in addition to dynamically creating a Tab button, we are also dynamically creating and Button control, Label control, and VBox container.

Line number 6 defines a varibale that will hold the number of Tab buttons created during runtime.

Lines 7 through 15 define the function that will add a new Tab button to theTabNavigator. First we create a new VBox on line 8 and a new Label on line 9. Next (line 10) we get the current number of Tab buttons on the TabNavigator using the numChildren property. The Tab buttons act as child controls on the TabNavigator. So we can easily get the number of children … the first child has an index of zero, the second has an index of one, and so on.

Now we define the label text for the new Panel (line 11) and the text for the new Label. These new objects have not been added to the display just yet.

The next tow lines (13 and 14) add the new objects as children of the containers. Line 13 says, “within the newVBox object add the child object called newLabel.” Line 14 says, “within the tn (TabNavigator) container add the child object called newVBox.” And there is your new Tab button complete with a label and a bit of text showing within the TabNavigator’s canvas.

So, lines 16 through 21 should not be so difficult to understand. On line 17 we first check to see if there are any Tab buttons on the TabNaviagtor by looking at the numChildren variable. If the value is greater than zero then we descrese the value in that variable.

On line 19 we remove the last Tab button (far right) from the TabNavigator by using the removeChildAt method. this method take the index position of the Tab button we wish to remove.

Conclusion: Good. So now you know how to dynamically add Tab buttons to a TabNavigator. using this bit of knowledge you should be able to figure how to add tab buttons based on a data model or results from a datasource. Now that’s really powerful.

About these ads
Comments
  1. Rajeev says:

    Hi,

    How can i add 4-5 tabs in tab navigator using loop and i need a datagrid to be dynamically generated in each tab

    plz find me some solution

  2. therush says:

    Hi Rajeev,

    Depending on when you want the tabs to appear, you can use much of the same actionscript code you see above. 1) Call the function after the Application’s creationComplete event. 2) Enter the loop. 3) Add the tabs.

    As far as the Datagrids go, you can use Actionscript to add datagrids as children in the Tab Navigator then specify your dataproviders for each datagrid.

    Hope that helps. Let me know if you need a more detailed example.

  3. Andres says:

    hi therush!, i read your post, it’s been very useful, but i cannot find a way to insert components inside a tab i tried uisng:

    var btn:Button=new Button();
    myTab.addChildAt(btn,0);

    but it doesn’t work…. actually i am trying to create dinamically the tabs and then reffer to them in order to insert the new components, but i just can’t find a way…

  4. therush says:

    Now do you mean inside the one of the Tab Navigator’s children OR inside the tab button itself?

  5. Yes i managed to get it working althought i donĀ“t know exactly why but when adding
    childs to the TabNavigator the last one is not actually added so i better insert
    the first at the beggining and the next ones insert them using addChildAt() which
    was for me the best solution as the code shows:
    lastTab();//a function that inserts the last row
    for(var i:int=0;i
    var tab:VBox=new VBox();
    tab.label=titles[i].split(“;”)[0]
    var
    addMore:int=parseInt(titles[i].split(“;”)[4]);
    var unu:usnUsed;
    this.addChildAt(tab,i);
    for(var h:int=0;h unu=new usnUsed();
    unu._inum=titles[i].split(“;”)[3]
    tab.addChild(unu);
    }

    the shortest explanation is:
    1) insert the last Tab first then use addChildAt() to insert them before the last
    2)when setting a new container the best solution for me was adding it to the
    display list before adding any new new display objects to that component

    finally i gotta say thanx for emailing me and well that code is part of the
    registration server i called laiza which you can find here http://www.asb-labs.com/laiza

    greetings!! Andres….(btw i sent you an email but it seems it was spam-assesined)

  6. ana says:

    Hi
    I have an mxml page which have four tabs each with form which need to be submitted to 4 different tables.(backend php)

    I am able to submit the data to the table but when i submit form4.. i will get 4 entries of form1 in table1.

    How can I get some identifier to my php page on which form or which button is clicked.

    Thanks

  7. Dan Hamm says:

    Interesting. I have a related problem, which I solved in a similar manner. I start out with one tab, and then need to add new ones (at the user’s request) in an arbitary order. For example, starting with a single tab, I might add a second tab to the right, and then a third between the first two. I always set selectedIndex to the position of the new tab. The new tab gets correctly selected if and only if I have clicked on a tab label (i.e. changed the selected index through the UI) between adding the second and third tabs. Otherwise, although I set selectedIndex to 1 (the middle of hte three) it is in fact the third tab (selectedIndex 2) that gets selected. The user can remedy by clicking on the correct tab label, but its a bit amateurish. Any ideas?

    Dan

  8. Dan Hamm says:

    Have now solved the above problem. It seems that the new properties do not get committed until there is some user interaction.

    The simple solution is to call function “commitProperties()” immediately BEFORE reassigning “selectedIndex”. However commitProperties() is a protected function, and can therefore only be called from a subclass of the original component. Therefore it is necessary to define a subclass (say TabNavigatorEx) and define a function setIndex() which calls commitProperties() before assigning selectedIndex. It would have been neater to override the selectedIndex setter, but this did not appear to be possible.

    5 lines of code, 5 hours to work out what was needed (OK, then, a couple of hours). Thus was it always.

    Dan

  9. Kevin says:

    Hi Theo,

    With regard to dynamic tabs. Can you point me in the right direction for the following:

    If datagrid item is selected then new dynamic tab is created and only one new tab is created. In other words once the datagrid has been clicked on no more new tabs will be created, just one.

    Lastly, how would I give the new tab created a specific label?

    Much appreciated.

  10. Kiran says:

    Hi Guys,

    I need to generate dynamic tab pages, each tab containing a form being generated from a xml source. So when i alter any of the form items, i need to update its value to its corresponding xmllist. How do i keep track of each form elements(like checkboxes, text inputs and radio buttons) in their respective tab if i add them dynamically? Can some body throw some light on it.

    Thanks in Advance.

  11. terrence says:

    hi Guys
    I’m new to Flex
    I have create a new flex WindowedApplication to load a website.

    i have a button in http://www.mysite.com.if i click that button it will open as a popup window. when i load that page into my flex application popup window doesn’t work.I need to open that popup window in tab. any idea ? below i have post my code

    <![CDATA[

    import mx.core.Application;
    import mx.events.CloseEvent;

    private function onClick(event:Event):void{
    if(event.currentTarget==urlButton){
    ClientBrowser.location=urlTextInput.text;
    }else if(event.currentTarget==backButton){
    ClientBrowser.historyBack();
    }else if(event.currentTarget==forwardButton){
    ClientBrowser.historyForward();
    }else{
    //do Nothing
    }

    }

    private function onApplicationComplete():void {
    stage.displayState = StageDisplayState.FULL_SCREEN_INTERACTIVE;

  12. Anonymous says:

    I cant see the Code. Just the Half of it.
    Resolution: 1204*768
    Browser: firefox 2.0.0.20

    regards

  13. satish says:

    Hi.

    I am creating a tabNavigator and I want to justify the first 4 tabs left, and the 5th tab I want to jusify right.

    Cheers

  14. Ken says:

    This works well to add tabs, but how to I put info on a newly created tab? Ideally I’d like to create a new tab with a datagrid on it driven by a xml file. The datagrid just presents a subset of the xml data, each tab/datagrid showing a subset of the whole xml data.

  15. Joel Schiffer says:

    I can’t reall see this code :/. It is like cut off at the right. Is it just me?

  16. Loreto Parisi says:

    Since someone was not able to read the code above…

    3. import mx.controls.Button;
    4. import mx.controls.Label;
    5. import mx.containers.VBox;

    6. public var numChild:Number = 0;

    7. public function addTab():void {
    8. var newVBox:VBox = new VBox();
    9. var newLabel:Label = new Label();

    10. numChild = tn.numChildren + 1;

    11. newVBox.label = “Panel ” + numChild;

    12. newLabel.text = “TabNavigator container panel ” +
    numChild;

    13. newVBox.addChild(newLabel);

    14. tn.addChild(newVBox);
    15. }

    16. public function removeTab():void {
    17. if(tn.numChildren > 0){
    18. numChild –;

    19. tn.removeChildAt(numChild);
    20. }
    21. }

  17. uma says:

    Thank you very much for giving this information.

  18. Very informative post! I have a follow up question: Do you know how to get the location property of a dynamically created tab that contains an HTML element? I’ve cribbed your code to dynamically create tabs that, when a user clicks on them, allow the user to surf the Web. I need to be able to keep a pulse on what web sites the user is surfing to in a particular tab so I added an event listener that calls a function. However, in the function I can’t access the location property. Here is the code I have so far:

    public function addTab():void {
    var newVBox:VBox = new VBox();

    numChild = tn.numChildren + 1;

    newVBox.label = “Panel ” + numChild;

    var newHTML:HTML = new HTML();
    newHTML.location = “http://www.wikipedia.org”;
    newHTML.id = “html” + numChild;
    newHTML.addEventListener(LocationChangeEvent.LOCATION_CHANGE,html_locationChange);
    newVBox.addChild(newHTML);

    tn.addChild(newVBox);
    }

    public function html_locationChange(evt:Event):void {

    //this function is called everytime the user surfs to a new address in the dynamically created tab
    //But how, in this function do I access the location (e.g. URL) that they have
    //surfed to?
    }

  19. suvrajit says:

    Hiii Good example dude nice work.
    Thank u

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s