CxJS

Tree Drag and Drop

Tree grids support drag and drop for moving nodes into folders and reordering within the hierarchy.

<Grid
  controller={PageController}
  records={m.files}
  recordAlias={m.$file}
  border
  dataAdapter={{ type: TreeAdapter }}
  keyField="id"
  columns={[
    {
      header: "Name",
      field: "name",
      items: (
        <TreeNode
          expanded={m.$file.$expanded}
          leaf={m.$file.$leaf}
          level={m.$file.$level}
          loading={m.$file.$loading}
          text={m.$file.name}
        />
      ),
    },
  ]}
  dragSource={{ mode: "copy", data: { type: "file" } }}
  onRowDropTest={(e) => e.source?.data?.type === "file"}
  onRowDragOver={(e) => {
    const target = e.target?.record?.data
    const source = e.source?.record?.data
    // Only allow dropping onto folders (not leaves) and not onto itself
    if (target?.$leaf || source?.id === target?.id) return false
  }}
  onRowDrop={(e, instance) =>
    instance.getControllerByType(PageController).onRowDrop(e)
  }
/>
Name
Documents
Pictures
Music
report.pdf
notes.txt
data.xlsx

Drag files into folders to move them.

Validating Drops

Use onRowDropTest to validate the drag source type and onRowDragOver to control where items can be dropped:

onRowDropTest={(e) => e.source?.data?.type === "file"}

onRowDragOver={(e) => {
  const targetNode = e.target?.record?.data;
  const sourceNode = e.source?.record?.data;
  // Only allow dropping onto folders, not leaves or self
  if (targetNode?.$leaf || sourceNode?.id === targetNode?.id) {
    return false;
  }
}}

Handling Drops

Use onRowDrop with updateTree to modify the tree structure:

import { updateTree } from "cx/data";

onRowDrop={(e) => {
  const sourceNode = e.source.record.data;
  const targetNode = e.target.record.data;

  const newTree = updateTree(
    store.get(m.files),
    (node) => ({
      ...node,
      $children: [...(node.$children || []), { ...sourceNode, id: nextId++ }],
    }),
    (node) => node.id === targetNode.id,
    "$children",
    (node) => node.id === sourceNode.id,
  );

  store.set(m.files, newTree);
}}

Configuration

PropertyTypeDescription
dragSourceobjectConfiguration for row dragging. Use mode: "copy" for tree operations.
onRowDropTestfunctionTest if dropping on a specific row is valid.
onRowDropfunctionHandle drop on a specific row.
onRowDragOverfunctionCalled when dragging over a row.
onDragEndfunctionCalled when drag operation ends.

See also: Row Drag and Drop, Tree Grid