minop1205 / react-dnd-treeview

A draggable / droppable React-based treeview component. You can use render props to create each node freely.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

initialOpen={true} is not working.

nilesh2b opened this issue · comments

@minop1205 Hi, I am using this package and it solves almost my all problems.
But I am not able to expand the dynamic node tree by using initialOpen attribute.
Thanks

@nilesh2b Thanks for the report.
It would be helpful to know the code and steps to reproduce it.

Or can't you use the open / close methods instead of the initialOpen API?

Reference below

https://github.com/minop1205/react-dnd-treeview#usage-to-open--close-methods

https://minop1205.github.io/react-dnd-treeview/?path=/docs/basic-examples-opening-and-closing-all-nodes--opening-and-closing-all-nodes-story

@minop1205 Thank you for your prompt response.
I wanted to open the tree on initial page load

<DndProvider backend={MultiBackend} options={getBackendOptions()}>
  <div>
    {open && (
      <AddDialog
        tree={treeData}
        onClose={handleCloseDialog}
        onSubmit={handleSubmit}
      />
    )}
  </div>
  <Tree
    tree={treeData}
    rootId={"0"}
    onDrop={handleDrop}
    initialOpen={true}
    classes={{ container: "wtree", listItem: "parent-listitem" }}
    render={(node, { depth, isOpen, hasChild, onToggle }) => (
      <CustomNode
        handleOpenDialog={handleOpenDialog}
        node={node}
        depth={depth}
        hasChild={hasChild}
        isOpen={isOpen}
        onToggle={onToggle}
        onTextChange={handleTextChange}
        onDelete={handleDelete}
        onCopy={handleCopy}
        dragPreviewRender={(monitorProps) => (
          <CustomDragPreview monitorProps={monitorProps} />
        )}
      />
    )}
  />
</DndProvider>;

The above mentioned code i have implemented.

@nilesh2b
Looking at the code, there doesn't seem to be anything strange about it.
It is odd that dragPreviewRender is a CustomNode props, but it does not seem to be related to the initialOpen issue.

The initialOpen API only handles the tree component when it is mounted, so it will not work on nodes added after it is mounted. If for any other reason it does not work as intended, please provide a repository or CodeSandbox that can reproduce the problem.

Yes you are right, nodes are added after it is mounted. In that case how I could open the tree on initial load.

Also running into a similar issue, where I want to dynamically switch out the tree (NodeModel[]) . My workaround is to manually keep track of open/closed nodes and pass an array into initialOpen instead. The problem with this is that the first render, after switching trees, will always have the nodes closed and then become open. This leads to some UI flashing.

I made a simple example with the workaround and wasn't able to reproduce the flashing so it may be due to application specific details

import {
  DndProvider,
  getBackendOptions,
  MultiBackend,
  NodeModel,
  RenderParams,
  Tree,
} from "@minoru/react-dnd-treeview";
import { useMemo, useState } from "react";

const ROOT_ID = "root-id";
const trees = [
  [0, 1, 2],
  [10, 11, 12],
];

function App() {
  const [treeIndex, setTreeIndex] = useState(0);
  
  const tree: NodeModel[] = useMemo(() => {
    return trees[treeIndex].map((t) => {
      return {
        id: t,
        parent: t === 0 || t === 10 ? ROOT_ID : t - 1,
        text: t.toString(),
        droppable: true,
      };
    });
  }, [treeIndex]);

  return (
    <div className="App">
      <button onClick={() => setTreeIndex((treeIndex + 1) % 2)}>
        swap trees
      </button>
      <DndProvider backend={MultiBackend} options={getBackendOptions()}>
        <Tree
          tree={tree}
          rootId={ROOT_ID}
          initialOpen={[0,1,2,10,11,12]}
          sort={false}
          insertDroppableFirst={false}
          render={renderNode}
          onDrop={onDrop}
        />
      </DndProvider>
    </div>
  );
}

function onDrop() {}

function renderNode(node: NodeModel, renderParams: RenderParams) {
  console.log(renderParams)
  return <div>{renderParams.isOpen ? 'open' : 'closed'} {node.text}</div>;
}

export default App;

The initialOpen API is calculated based on the tree data at the time the value changes.
Therefore, if the initialOpen value has not changed, or if the tree data does not exist at the time the initialOpen value changes, the intended display will not be obtained.

There are three possible ways to set initialOpen for lazy-loaded tree data.
Samples of each are provided for your reference.

  1. do not render components until tree data is loaded
    https://codesandbox.io/s/issue175-sample1-rrl3c8?file=/src/App.jsx

  2. open any node using the open of openAll method after the tree data is loaded
    https://codesandbox.io/s/issue175-sample2-0qzr3m?file=/src/App.jsx

  3. update the initialOpen property when the tree data is loaded
    https://codesandbox.io/s/issue175-sample3-v1z1hs?file=/src/App.jsx

Just a hint:
If you use initialOpen={true} make sure that your tree items have IDs counting from 0 ... otherwise you should use initialOpen=[desired-IDs].

Hope this will help! ;)