Open edgesoft opened 9 years ago
How large is the tree?
More than 10.000 nodes ( Not for every user. Some has just 100 ). All won't expand every time a user works in the tree.
Are you not able to do that in renderNode? You could update the tree when a node is selected.
Let's say I want to move a node with many children to another nodes child. I need to expand the node on hover and then fetch data from server. And then be able to hover yet another node that was just fetched and fetch until the user finds which node he/she wants to move to. I need to refresh on hover and expand lazily. I don't know how to accomplish that right now.
@wangzuo Proposing to add lazy boolean to the tree. If the tree is lazy then we should check index.hasChildren and not just index.children && index.children.length. An onBeforeOpenNode event should be called in toggleCollapse to allow fetching data from server before we expand.
{ module: 'parent', leaf: false, hasChildren: true }
Something like this so far. This will enable lazyloading per node.
modules
{
module: 'test',
leaf: false,
hasChildren: true,
collapsed: true,
lazy: true
}
react-ui-tree.js
toggleCollapse(nodeId) {
var tree = this.state.tree;
var index = tree.getIndex(nodeId);
var node = index.node;
if( this.props.onLazyloadNode && node.lazy && node.hasChildren ){
node.lazy = false;
this.props.onLazyloadNode(node, function(nodes){
nodes.map( newNode => {
tree.append(newNode,nodeId);
} );
this.makeToggleUpdate(node);
}.bind(this));
}else{
this.makeToggleUpdate(node);
}
},
makeToggleUpdate(node){
var tree = this.state.tree;
node.collapsed = !node.collapsed;
tree.updateNodesPosition();
this.setState({
tree: tree
});
this.change(tree);
}
node.js. Updated node.hasChildren
renderCollapse() {
var index = this.props.index;
var node = index.node;
if(node.hasChildren || (index.children && index.children.length)) {
var collapsed = index.node.collapsed;
return (
<span
className={cx('collapse', collapsed ? 'caret-right' : 'caret-down')}
onMouseDown={function(e) {e.stopPropagation()}}
onClick={this.handleCollapse}>
</span>
);
}
return null;
},
exampel app.js
<Tree
paddingLeft={20}
tree={this.state.tree}
onChange={this.handleChange}
isNodeCollapsed={this.isNodeCollapsed}
renderNode={this.renderNode}
shouldRenderRootNode={true}
onLazyloadNode={this.onLazyloadNode}
/>
onLazyloadNode(node,cb){
console.log( "Before expand" );
setTimeout(function(){
var nodes = [
{module: 'mathias', leaf: false, collapsed: true, lazy: true,hasChildren : true}
];
cb( nodes );
console.log( "After expand" );
},2000);
},
This seems like a good improvement that will become more necessary as the amount of nodes increase. I have a project that has around 5000 nodes and it can get quite slow.
Should the suggested changes be in a pull request?
Thanks! will try to add this feature.
@wangzuo I didn't commit this yet but accepted the pull request from @tobyndockerill because there is still a problem to solve. When clicking the expand arrow multiple times we should have a behaviour. What should happen? Right now we set the lazy to false so that we don't fetch data from server again. But the toggle is slow an feels unresponsive. Should we lock the node currently lazyloading to prevent toogle when loading? Have a spinner? any suggestions?
The best suggestion so far is to lock click on the arrow and show a svg spinner instead of the arrow. Is this a good solution? @wangzuo @tobyndockerill
I agree. A loading indicator would go a long way to show the user that something is happening behind the scenes.
I am also super interested in this, drag and drop becomes extremely slow even in a moderately sized tree
I'm interested in this too, any chance there's going to be a PR for this soon?
I'd love to see this feature implemented as well. It would help immensely, and it is a very nice thing to have anyway.
I have a very large tree that I won't be able to load on initialization. Would it be possible to do lazy loading? A user clicks on a node and fetches data from server and adds it to the tree. We would need some way of telling the node that it has children but it should be loaded from the server.