moveTreeViewItem

A helper function which moves a TreeView item in an immutable way.

class App extends React.Component {
    dragClue;
    state = { tree };

    render() {
        return (
            <div>
                <TreeView data={this.state.tree} draggable={true}
                    onItemDragOver={this.onItemDragOver} onItemDragEnd={this.onItemDragEnd} />
                <TreeViewDragClue ref={dragClue => this.dragClue = dragClue} />
            </div>
        );
    }

    onItemDragOver = (event) => {
        this.dragClue.show(event.pageY + 10, event.pageX, event.item.text, this.getClueClassName(event));
    }
    onItemDragEnd = (event) => {
        this.dragClue.hide();
        const eventAnalyzer = new TreeViewDragAnalyzer(event).init();

        if (eventAnalyzer.isDropAllowed) {
            const updatedTree = moveTreeViewItem(
                event.itemHierarchicalIndex,
                this.state.tree,
                eventAnalyzer.getDropOperation(),
                eventAnalyzer.destinationMeta.itemHierarchicalIndex,
            );

            this.setState({ tree: updatedTree });
        }
    }
    getClueClassName(event) {
        const eventAnalyzer = new TreeViewDragAnalyzer(event).init();
        const itemIndex = eventAnalyzer.destinationMeta.itemHierarchicalIndex;

        if (eventAnalyzer.isDropAllowed) {
            switch (eventAnalyzer.getDropOperation()) {
                case 'child':
                    return 'k-i-plus';
                case 'before':
                    return itemIndex === '0' || itemIndex.endsWith(`${SEPARATOR}0`) ?
                        'k-i-insert-up' : 'k-i-insert-middle';
                case 'after':
                    const siblings = getSiblings(itemIndex, this.state.tree);
                    const lastIndex = Number(itemIndex.split(SEPARATOR).pop());

                    return lastIndex < siblings.length - 1 ? 'k-i-insert-middle' : 'k-i-insert-down';
                default:
                    break;
            }
        }

        return 'k-i-cancel';
    }
}

function getSiblings(itemIndex, data) {
    let result = data;

    const indices = itemIndex.split(SEPARATOR).map(index => Number(index));
    for (let i = 0; i < indices.length - 1; i++) {
        result = result[indices[i]].items;
    }

    return result;
}

const SEPARATOR = '_';
const tree = [{
    text: 'Furniture', expanded: true, items: [
        { text: 'Tables & Chairs', expanded: true },
        { text: 'Sofas', expanded: true },
        { text: 'Occasional Furniture', expanded: true }]
}, {
    text: 'Decor', expanded: true, items: [
        { text: 'Bed Linen', expanded: true },
        { text: 'Curtains & Blinds', expanded: true },
        { text: 'Carpets', expanded: true }]
}];

ReactDOM.render(<App />, document.querySelector('my-app'));

Parameters

sourceItemHierarchicalIndex string

The hierarchical index of the item that will be moved.

sourceData any[] | null | undefined

The tree which contains the item that will be moved.

operation "before" | "after" | "child"

The specific move operation.

The available options are:

  • before—Indicates that the source item will become the previous sibling of the target item.
  • after—Indicates that the source item will become the next sibling of the target item.
  • child—Indicates that the source item will become a child of the target item.
targetItemHierarchicalIndex string

The hierarchical index of the item next to which the source item will be moved.

targetData? any[] | null

The tree which contains the target item. If the argument is skipped, then the move operation will be executed within the same tree. Setting the sourceData and targetData arguments to the same tree is also supported.

Returns

any[] | { sourceData: any[]; targetData: any[]; } - The updated copies of the sourceData and targetData input arguments. If targetData is not passed, then only the updated copy of the sourceData will be returned.

 /