score:0

doing this recursively is a good way to go about this. what you can do is to give each list item element an onclick handler.

<li onclick={this._togglechildreninit.bind(this, item.id)}>

i don't know much about what you're id's are like. but consider the following structure:

{id: "0", isopen: false, children: [
  {id: "0.0", isopen: false, children: [
    {id: "0.0.0", isopen: false, children: null},
    {id: "0.0.1", isopen: false, children: null}
  ]},
  {id: "0.1", isopen: false, children: null}
]}

the id for each child is the id of the previous parent, plus a "." and the number of order within that level.

you can then, with recursion, check if the desired item with some x id could be a child of an item, and start traversing that child the same way. this way, you don't have to traverse all items in the tree.

of course, this may vary from application to application, but hopefully it provides a clue of how you could approach this.

the code for the recursion triggered by the click is as follows:

_togglechildreninit = (data_id) => {
  var result = this._togglechildren(0, data_id, this.state.listobject);
 this.setstate({listobject: result});
}

_togglechildren = (i, data_id, arr) => {
  if (i <= arr.length-1) {
    if (arr[i].id == data_id && arr[i].children.length > 0) {
      arr[i].isopen = !arr[i].isopen;
    } else {
      var newarr = this._togglechildren(0, data_id, arr[i].children);
      arr[i].children = newarr;
      if (arr[i].id.charat(0) != data_id.charat(0)) {
        arr[i].isopen = false;
      }
    }
    arr = this._togglechildren(++i, data_id, arr);
  }
  return arr;
}

edit - alternative structure

if your object looks like this:

{id: "0", isopen: false, children: [
  {id: "1", isopen: false, children: [
    {id: "2", isopen: false, children: null},
    {id: "3", isopen: false, children: null}
  ]},
  {id: "4", isopen: false, children: null}
]}

you can use this instead:

_togglechildreninit = (data_id) => {
  var result = this._togglechildren(0, data_id, this.state.listobject);
 this.setstate({listobject: result});
}

_togglechildren = (i, data_id, arr) => {
  if (i <= arr.length-1) {
    if (arr[i].id == data_id && arr[i].children.length > 0) {
      arr[i].isopen = !arr[i].isopen;
    } else {
      var newarr = this._togglechildren(0, data_id, arr[i].children);
      arr[i].children = newarr;
      if (arr[i].id < data_id) {
        arr[i].isopen = false;
      }
    }
    arr = this._togglechildren(++i, data_id, arr);
  }
  return arr;
}

score:4

are you trying to simulate accordion behaviour? if yes then you can modify your code like this. use component's state and toggle it to open and close children. instead of creating <list list={item.children} /> in list class, import(or use require) list.js in list-item.js and render the child list item on the basis of current listitem's state.

list-item.js

class listitem extends react.component {
  //add this
  constructor (){
      super(...arguments);
      this.state = { showchild:false};
  }

  handlecollapse(){
      console.log('open/close: ' + this.props.item.display_name);
      //add this
      this.setstate({showchild:!this.state.showchild});
      return false;
  }

  handlefilter(){
      console.log('filter id: ' + this.props.item.id);
      return false;
  }

  render(){
      let children;
      if(this.state.showchild) {
          children = (<list list={this.props.item.children} />);
      }

      return (
          <div>
              <a rel="{this.props.item.id}" onclick={this.handlecollapse.bind(this)}>
            {this.props.item.display_name}
              </a>
              <input value="" type="checkbox" onclick={this.handlefilter.bind(this)} />
             //add this
             {children}
          </div>
      )
  };
}

list.js

class list extends react.component {

    render(){
        //removed <list .../>, rest is same just other way of doing same stuff
        let li = this.props.list.map( (item) => {
            return( <li> <listitem key={item.id} item={item} /></li>);
        }
     );

        return ( <ul>{li}</ul>);
  }

};

dummy data to test

var data=[
  {
      id:"1st of level 1",
      get display_name(){return _name(this.id,this.children)},
      children: [
          {
              id:"1st of level 1.2",
              get display_name(){return _name(this.id,this.children)},
              children: [
                  {
                      id:"1st of level 1.2.1",
                      get display_name(){return _name(this.id,this.children)},
                      children:[]
                  }
              ]
          },

          {
              id:"2nd of level 1.2",
              get display_name(){return _name(this.id,this.children)},
              children:[]
          }
      ]
  },

  {
      id:"2nd of level 1",
      get display_name(){return _name(this.id,this.children)},
      children:[]
  },

  {
      id:"3rd of level 1",
      get display_name(){return _name(this.id,this.children)},
      children:[]
   },

   {
       id:"4th of level1",
       get display_name(){return _name(this.id,this.children)},
       children:[]
   }

 ];

function _name(id,child) {
    if(child.length>0)
        return("i am "+id+" i have children");
    else {
        return("i am "+id+" i don't have children ");
    }    
}


reactdom.render(<list list={data} />,document.getelementbyid('root'));

`


Related Query

More Query from same tag