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

undefined | "null" | any[]

The tree which contains the item that will be moved.
operation

"after" | "before" | "child"

The specific move operation.

The available options are:

  • beforeIndicates that the source item will become the previous sibling of the target item.
  • afterIndicates that the source item will become the next sibling of the target item.
  • childIndicates 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?

"null" | any[]

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.
childrenField?

string

The field that points to the dataItem sub items. Defaults to `items`.

Returns

undefined | "null" | any[] | { sourceData: undefined | "null" | 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.