1

I'm trying to build a Tree Table that is capable of shown/hide their TR childs when clicked (among other things).

I've grab some code from the web to generate easily generate a tree structure. The problem comes trying to set a parent/child relationship with this event. I'm really not used to react so it is hard for me to understand certain things.

This is the data structure:

var data = [
  {
    id: 1,
    label: 'Order 1',
    deep: 0,
    children: [{
      id: 11,
      label: 'Cycle November',
      deep: 1,
    },
    {
      id: 12,
      label: 'Cycle December',
      deep: 1,
    }]
  },
  {
    id: 2,
    label: 'Order 2',
    deep: 0,
    children: [{
      id: 21,
      label: 'Cycle January',
      deep: 1
    }]
  },
];

Then i want to click on Parent id 1 and see who their children are.

This is the code that draws the Table:

var TR = React.createClass({
  childs: [],
  hasParent: function() {
    if (this.props.parent) {
      return true;
    }
    else {
      return false;
    }
  },
  componentDidMount: function(){
    if (this.hasParent()) {
      parentKey = this.props.parent.props.keyId.split('-')[1];
      thisKey   = this.props.keyId.split('-')[0];
      if (parentKey == thisKey) {
        console.log('I set the child'); 
        this.props.parent.props.childs.push(this);
      }
    }
  },
  handleClick: function(event) {
    if (this.hasParent()) {
      parent = this.props.parent;
      console.log('My father is: '+parent.props.keyId);
      console.log('Me and my brothers are: ');
      parent.props.childs.map(function(child) {
        console.log(child.props.keyId);
      });
    }
    else {
      console.log('I am: '+this.props.keyId);
      console.log('My children are:');
      this.props.childs.map(function(child) {
        console.log(child.props.keyId);
      });
    }
  },
  isShown: function() {
    return false;
  },
  getDefaultProps: function() {
      return {
        childs: new Array(),
      };
  },
  render: function() {
    var iparent = this.props.data.deep*20;

    return (
        <tr>
          <td style={{paddingLeft: iparent+'px'}}>
            <span onClick={this.handleClick} >
            &nbsp; + </span>
            {this.props.data.label}
          </td>
        </tr>
    );
  }
});

var Tree = React.createClass({
  render: function() {
    var treeItems = [];
    parent = null;
    var renderTreeItems = function(items, parent) {
      if (!items) {
        return;
      }
      for (var i = 0; i < items.length; i++) {
        if (items[i].deep == 0) {
          var parent_id = items[i].deep;
        }
        else {
          var parent_id = parent.props.data.id;
        }
        var key = parent_id+'-'+items[i].id;

        tr = (
          <TR key={key} keyId={key} data={items[i]} parent={parent} >
          </TR>
        );
        treeItems.push(
          tr
          );
        renderTreeItems(items[i].children, tr);
      }
    };
    renderTreeItems(this.props.data);
    return (
      <table>
        { treeItems }
      </table>
    );
  }
});

And last the HTML to attach the component:

<html>
    <body>
        <div id="tree"></div>
        <script type="text/jsx">
            React.render(<Tree data={data}/>, document.body);
        </script>
    </body>
</html>

The actual problem is that childs (badly written i know...) seems to be shared between all TR instances. Can someone point what i'm doing wrong and what is the best approach to deal with this? Simply: i want to hide/show childs clicking on the TR-First TD that "acts" as a parent.

Here is the jsfiddle http://jsfiddle.net/69z2wepo/2731/

1 Answer 1

1

I approached the problem from a new perspective using a parent_key on every TR and querying against all the array in search of those objects that have that parent_key, changing it's properties. Now I have the start of a fully functional table tree.

//Won't work below IE9, but totally safe otherwise
!function() {
    function _dynamicSortMultiple(attr) {
       /*
        * save the arguments object as it will be overwritten
        * note that arguments object is an array-like object
        * consisting of the names of the properties to sort by
        */
       var props = arguments;
       return function (obj1, obj2) {
           var i = 0, result = 0, numberOfProperties = props.length;
           /* try getting a different result from 0 (equal)
            * as long as we have extra properties to compare
            */
           while(result === 0 && i < numberOfProperties) {
               result = _dynamicSort(props[i])(obj1, obj2);
               i++;
           }
           return result;
      };
    }
    function _dynamicSort(property) {
        var sortOrder = 1;
        if(property[0] === "-") {
            sortOrder = -1;
            property = property.substr(1);
        }
        return function (a,b) {
            var result = (a[property] < b[property]) ? -1 : (a[property] > b[property]) ? 1 : 0;
            return result * sortOrder;
        }
    }
    Object.defineProperty(Array.prototype, "sortBy", {
        enumerable: false,
        writable: true,
        value: function() {
            return this.sort(_dynamicSortMultiple.apply(null, arguments));
        }
    });
}();

var TD = React.createClass({
    onHandleClick: function(event) {
        this.props.onHandleClick(this.props.data.key);
    },
    render: function() {
        var iparent = this.props.data.deep*20;
        var icon = "fa-chevron-down";

        return (
            <td style={{paddingLeft: iparent+'px'}}>
                <span onClick={this.onHandleClick} className={"fa "+icon}>
                &nbsp;</span>
                {this.props.data.label}
            </td>
        );
    }
})

var TR = React.createClass({
  onHandleClick: function(TD) {
    this.props.onHandleClick(TD);
  },
  render: function() {
    if (this.props.data.isShown) {
        return (
        <tr>
            <TD data={this.props.data} onHandleClick={this.onHandleClick}/>
        </tr>
        );
    }
    else {
        return (
            <tr>
            </tr>
        );
    }
  }
});

var List = React.createClass({
  render: function() {
    var self = this;
    var trs = this.props.data.map(function(row) {
      var key = row.deep+'-'+row.id;
      return (<TR key={key} keyId={key} parentKey={row.parent_key} data={row} onHandleClick={self.props.onHandleClick} />);
    });

    return (
      <table>
        {trs}
      </table>
    );
  }
});

var Tree = React.createClass({
  handleClick: function(key) {
    newState = this.state.data.slice();
    for (var i = newState.length - 1; i >= 0; i--) {
        var item = newState[i];
        if (item.parent_key == key) {
            item.isShown = (item.isShown)?false:true;
            newState[i] = item;
        }
    };
    this.setState({data: newState});
  },
  loadFromServer: function() {
    var data = [
      {
        id: 1,
        label: 'Order 1',
        deep: 0,
        key: '0-1',
        parent_key: '0',
      },
      {
        id: 11,
        label: 'Cycle November',
        deep: 1,
        key: '0-1-11',
        parent_key: '0-1',
      },
      {
        id: 12,
        label: 'Cycle December',
        deep: 1,
        key: '0-1-12',
        parent_key: '0-1',
      },
      {
        id: 2,
        label: 'Order 2',
        deep: 0,
        key: '0-2',
        parent_key: '0'
      },
      {
        id: 21,
        label: 'Cycle January',
        deep: 1,
        key: '0-2-21',
        parent_key: '0-2',
      }
    ];
    newState = [];
    data.map(function(item) {
        item.isShown = (item.deep != 0)?false:true;
        newState.push(item);
    });
    newState.sortBy("key");
    this.setState({data:newState});
  },
  getInitialState: function() {
    return {data: []};
  },
  componentDidMount: function() {
    this.loadFromServer();
  },
  render: function() {
    return (
      <div className="Box">
        <table className="table table-striped table-hover dataTables-orders" >
          <thead>
          </thead>
          <List data={this.state.data} onHandleClick={this.handleClick} />
        </table>
      </div>
    );
  }
});
React.render(<Tree data={data}/>, document.getElementById('tree'));
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.