Titanium Community Questions & Answer Archive

We felt that 6+ years of knowledge should not die so this is the Titanium Community Questions & Answer Archive

Expandable Table View Row - like Tree

Is there an easy (built-in to Titanium Mobile) way to make a Table View Row expand (and show) more rows when clicked on, and then make those rows also hide/collapse if the "master" Table View Row is clicked on again?

Similar to how Folder Tree Views work with subfolders on the desktop..?

— asked September 11th 2010 by Takahito Torimoto
  • collapse
  • expand
  • mobile
  • tableview
  • tree
1 Comment
  • Hello Torimoto,
    can you find an easy way to make it?

    Thanks!

    — commented October 4th 2010 by Gilliard Lopes

6 Answers

  • I was able to make a table row expand and contract by:

    row.addEventListener('click',function(e){
        if (e.row.expanded) {
            e.row.height=32;
            e.row.expanded=false;
        } else {
            e.row.height=57;
            e.row.expanded=true;
        }
    });
    

    And then make sure you set the initial height:

    row.height = 32;
    

    I've added labels to the row that have a "top" property of 34, so that when the row is not expanded the label elements are hidden. This is a way to create an "expandable" row.

    I'm new to Titanium Developer, but I suspect that you could add a window element to the row with a top property of 34, and then add a table element with table rows into that window in order to get the expanded main row to show our fabricated "child" rows. If anyone can confirm this is possible or knows a better way please post! Titanium Developer is in desperate need of documentation.

    — answered March 10th 2011 by Joe iEntry
    permalink
    1 Comment
    • Is it possible to expand/collaps rows instantly? Right now, when the row is clicked, there's some sort of default shift-down animation for rows below.

      — commented February 16th 2012 by Alex Raz
  • /**
     * Expadable/ collapsable tableview for iOS.
     * @author Gerben Hofman
     */
    var FoodBank = [];
    var win = Ti.UI.createWindow({  
        backgroundColor:    "blue",
        layout:                "vertical"
    });
    
    function Food(head, backgroundColor, parentIndex, expand, childs){//Food object
        this.title =                 head;
        this.backgroundColor =         backgroundColor;
        this.parentIndex =             parentIndex;
        this.expand =                 expand;
        this.childs =                 childs;
        this.rightImage =             "/images/rowArrowRight.png";
    }
    
    function EmptyRow(){//EmptyRow object
        this.backgroundColor = "green";//change this to transparent to make the rows invisible
        this.selectedBackgroundColor = "transparent";
        this.ignore = true;
    }
    
    var fruit = new Food("Fruit", "transparent", 0, true, [
        {name:"Apple"},
        {name:"Mango",},
        {name:"Banana"},
        {name:"Orange"}]
    );
    
    var vegetable = new Food("Vegetable", "transparent", 1, true, [
        {name:"Carrot"},
        {name:"Potatoe"},
        {name:"Bringal"},
        {name:"Cabbage"}]
    );
    
    FoodBank.push(fruit);
    FoodBank.push(vegetable);
    
    for(var i = 0; i <= 4; i++)//add EmptyRow objects to the FoodBank. It needs 5 EmptyRow objects to escape the ugly animation which you get with too few tableViewRows
        FoodBank.push(new EmptyRow());//this also bypasses the no row found error
    
    var table = Ti.UI.createTableView({
      data:                    FoodBank,
      height:                 Ti.UI.FILL,
      layout:                 "vertical",
      separatorColor:         "transparent",
      backgroundColor:        "transparent"
    });  
    
     /**
      * Event listener on table which handles the expanding/ collapsing of the childs. 
      * Parsing to int because the event callback is String. Int is needed to define next row index in insertRowAfter(); 
      * Also handles child clicks.
      */
    table.addEventListener("click", function(e){
        if(e.rowData.ignore){//empty row click
            console.log("Ignored");  
            return;//do nothing
        }
        var index = parseInt(e.index);//e callback is String, parse to int        
        var tableItem = e.rowData;//get table data    
        var parentIndex = parseInt(tableItem.parentIndex);//get parent index and parse to int
        if(!parentIndex && index > 0){//clicked child
            console.log("You've clicked child " + index);
            return;
        }
        if(tableItem.expand){//if expand is true expand the elements
            tableItem.expand = false;//will collapse on next click       
            tableItem.rightImage = "/images/rowArrowDown.png";
            for(var i in tableItem.childs){//loop through childs
                var child = tableItem.childs[i];//fetch child
                var row = Ti.UI.createTableViewRow({
                    layout:             "vertical",
                    height:             44,
                    backgroundColor:     "pink"
                });
                var label = Ti.UI.createLabel({
                    text:                 child.name,//set name
                    height:                Ti.UI.SIZE,
                    color:                "red",
                    font:                 {
                                            fontWeight:"bold",
                                        }
                });             
                row.add(label);       
                table.insertRowAfter(parseInt(i) + index, row);
            }        
            console.log("Expanded parent " + index);
        }else if(!tableItem.expand){//if expand is false collapse the elements
            tableItem.expand = true;//will expand on next click
            tableItem.rightImage = "/images/rowArrowRight.png";
            for(var i in tableItem.childs)//loop through childs
                table.deleteRow(index + 1);   
            console.log("Collapsed parent " + index);     
        }
    }); 
    
    win.add(table);
    win.open();
    
    — answered December 9th 2014 by Gerben Hofman
    permalink
    0 Comments
  • https://gist.github.com/946647 this link only show the parent data.can anybody help me for "How to expand a table view OR how to collaps the view?"

    — answered November 27th 2012 by pooja yadav
    permalink
    1 Comment
    • Hi Pooja,
      did u got the solution if so pls share.im also facing the same issue.thanks

      — commented June 21st 2013 by Aparna M
  • This works fine:

    var win = Ti.UI.createWindow({ backgroundColor: '#fff' });
    win.open();
    var container = Ti.UI.createView({backgroundColor: "white", layout: "vertical"});
    
    var layout = [
    
        {
            title: "Parent 1",
            isparent: true,
            opened: false,
            sub: [
                {
                    title: "Child 2"
                },
                {
                    title: "Child 1"
                }
            ]
        },
        {
            title: "Parent 2",
            isparent: true,
            opened: false,
            sub: [
                {
                    title: "Child 4"
                },
                {
                    title: "Child 3"
                }
            ]
        }
    
    ];
    var tableView = Ti.UI.createTableView({
        style:Titanium.UI.iPhone.TableViewStyle.GROUPED,
        top: 0,
        height: Ti.Platform.displayCaps.platformHeight,
        data: layout
    });
    
    
    tableView.addEventListener("click", function(e) {
    
        //Is this a parent cell?
        if(e.row.isparent) {
    
            //Is it opened?
            if(e.row.opened) {
                for(var i=e.row.sub.length; i > 0; i = i - 1) {
                    tableView.deleteRow(e.index + i);
                }
                e.row.opened = false;
            }
    
            else {
                //Add teh children.
                var currentIndex = e.index;
    
                for(var i=0; i < e.row.sub.length; i++) {
                    tableView.insertRowAfter(currentIndex, e.row.sub[i]);
                    //currentIndex++;
    
                }
                e.row.opened = true;
            }
    
        }
    
    });
    
    container.add(tableView);
    win.add(container);
    

    Reference : here

    — answered January 23rd 2014 by Kirthika VijayaKumar
    permalink
    4 Comments
    • Hey Krithika, This will work fine, but it seems, using this way we can add only title to the sub chid items. Do you know how to add labels or views as child of the table view row ?

      — commented April 15th 2014 by Kris Chan
    • Its only expanding..how to collapse the row???

      — commented May 8th 2014 by Aparna M
    • Hi Kris,
      check this:

      Titanium.UI.setBackgroundColor('#000');
      
      var win = Titanium.UI.createWindow({  
          title:'Tab 1',
          backgroundColor:'#fff',
          layout:'vertical'
      });
      
      var Data=[
          {
              title:"Fruit",
              option:0,
              press:0,
              element:[
              {name:'Apple',image:'KS_nav_views.png'},
              {name:'Mango',image:'KS_nav_views.png'},
              {name:'Banana',image:'KS_nav_views.png'},
              {name:'Orange',image:'KS_nav_views.png'}]
          },
      
          {
              title:'Vegetable',
              press:0,
              option:1,
              element:[
              {name:'Carrot',image:'KS_nav_ui.png'},
              {name:'Potatoe',image:'KS_nav_ui.png'},
              {name:'Bringal',image:'KS_nav_ui.png'},
              {name:'Cabbage',image:'KS_nav_ui.png'}]
          }
      ];
      
      
      var table = Ti.UI.createTableView({
        data:Data
      });
      
      
      table.addEventListener('click', function(e) 
      {
          if(Data[e.rowData.option].press==0)
          {
              Data[e.rowData.option].press=1;
      
      
              for (var i=0; i < e.rowData.element.length; i++)
              {
                  var row = Ti.UI.createTableViewRow({
                      layout : 'vertical'
                  });
                  var lbl=Ti.UI.createLabel({
                      text:e.rowData.element[i].name,
                      height:Ti.UI.SIZE,
                      color:'red',
                      font:
                      {
                          weight:'bold',
                      }
                  });
      
                  var anImageView = Ti.UI.createImageView({
                      image : e.rowData.element[i].image,
                  });
      
                  var Switch = Ti.UI.createSwitch({
                    value:true,
                    style:Titanium.UI.Android.SWITCH_STYLE_CHECKBOX
                  });
                  row.add(lbl);
                  row.add(anImageView);
                  row.add(Switch);
                  table.insertRowAfter(e.index+i,row);
      
              };
      
          }
          else
          {
              Data[e.rowData.option].press=0;
              for (var i =0;i< e.rowData.element.length;i++) 
              {
                  table.deleteRow(e.index+1);
              }
          }
      });
      
      
      win.add(table);
      win.open();
      

      — commented May 13th 2014 by Aparna M
    • Make sure to parse e.index and i to integer with parseInt() in table.insertRowAfter(). This will escape the "no row found error". Explanation: e.index is a String and i is an integer. Let's say e.index = 2 and i = 1. InstertRowAfter() wants to add a row after row 21(String 2 + integer 1 = 21) which doesn't exist in this case and this will result in a no row found error.

      — commented December 9th 2014 by Gerben Hofman
  • Kris Chan : Yup we can add only title and subtitle. I have no idea on adding labels and views. Sorry.

    Aparan : It does collapse also. Check it out.

    — answered May 12th 2014 by Kirthika VijayaKumar
    permalink
    1 Comment
    • Thanks Krithika !!

      — commented July 24th 2014 by Kris Chan
The ownership of individual contributions to this community generated content is retained by the authors of their contributions.
All trademarks remain the property of the respective owner.