External Form

The data of the KendoReact TreeList can be edited by using an external form.

import React from 'react';
import ReactDOM from 'react-dom';
import { TreeList, mapTree, extendDataItem, removeItems } from '@progress/kendo-react-treelist';
import employees from './data';
import EditingDialog from './EditingDialog.jsx';
import cellWithEditing from './cellWithEditing.jsx';

const subItemsField = 'employees';
const expandField = 'expanded';
const editField = 'inEdit';

class App extends React.Component {
    state = {
        data: [ ...employees ],
        itemInEdit: undefined,
        expanded: [1, 2, 32],
    };

    edit = (dataItem) => {
        this.setState({
            itemInEdit: extendDataItem(dataItem, subItemsField)
        });
    }

    remove = (dataItem) => {
        this.setState({
            data: removeItems(this.state.data, subItemsField, i => i.id === dataItem.id)
        });
    }

    editCell = cellWithEditing(this.edit, this.remove);

    save = () => {
        const { itemInEdit } = this.state;

        this.setState({
            itemInEdit: undefined,
            data: mapTree(
                this.state.data,
                subItemsField,
                item => itemInEdit.id === item.id ? itemInEdit : item
            )
        });
    }

    cancel = () => {
        this.setState({ itemInEdit: undefined });
    }

    render() {
        const { expanded, data } = this.state;
        return (
            <div >
                <TreeList
                    data={
                        mapTree(data, subItemsField, item =>
                            extendDataItem(item, subItemsField, {
                                [expandField]: expanded.includes(item.id)
                            })
                        )
                    }
                    style={{ maxHeight: '510px', overflow: 'auto' }}
                    editField={editField}
                    expandField={expandField}
                    subItemsField={subItemsField}
                    onExpandChange={this.onExpandChange}
                    columns={[
                        { field: "name", title: "Employee", expandable: true },
                        { field: "position", title: "Position" },
                        { field: "fullTime", title: "Full Time" },
                        { title: "Edit", cell: this.editCell }
                    ]}
                />
                {this.state.itemInEdit &&
                    <EditingDialog
                        itemInEdit={this.state.itemInEdit}
                        onChange={this.onItemChange}
                        save={this.save}
                        cancel={this.cancel}
                    />
                }
            </div>
        );
    }

    onItemChange = (itemInEdit) => {
        this.setState({
            itemInEdit
        });
    }

    onExpandChange = (e) => {
        this.setState({
            expanded: e.value ?
                this.state.expanded.filter(id => id !== e.dataItem.id) :
                [ ...this.state.expanded, e.dataItem.id ]
        });
    }
}

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

Setup

The following example utilizes the KendoReact Dialog as a modal form for editing the data of the TreeList.

  1. When a record is in edit mode, show the editing dialog and pass the edited item to it.

    {this.state.itemInEdit &&
        <EditingDialog
            itemInEdit={this.state.itemInEdit}
            onChange={this.onItemChange}
            save={this.save}
            cancel={this.cancel}
        />
    }
  2. Inside EditingDialog, bind the editors to the value of the row data.

    <form onSubmit={this.preventDefault}>
        <div style={{ marginBottom: '1rem' }}>
            <label>
                Employee<br />
                <input
                    type="text"
                    name="name"
                    className="k-textbox"
                    value={this.props.itemInEdit.name || ''}
                    onChange={this.onInputChange}
                />
            </label>
        </div>
        <div style={{ marginBottom: '1rem' }}>
            <label>
                Position<br />
                <input
                    type="text"
                    name="position"
                    className="k-textbox"
                    value={this.props.itemInEdit.position || ''}
                    onChange={this.onInputChange}
                />
            </label>
        </div>
        <div>
            <label>
                <input
                    type="checkbox"
                    name="fullTime"
                    checked={this.props.itemInEdit.fullTime || false}
                    onChange={this.onInputChange}
                />
                Full Time
            </label>
        </div>
    </form>
  3. Handle the change events of the editors. To update the TreeList edited item, update the itemInEdit property in the application state of the TreeList.

    export default class EditingDialog extends React.Component {
        onInputChange = (event) => {
            const { itemInEdit } = this.props;
            const input = event.target;
    
            // Will call the `onItemChange` function from the app.
            this.props.onChange.call(undefined, {
                ...itemInEdit,
                [input.name]: input.type === 'checkbox' ? input.checked : input.value
            });
        }
    }
    
    class App extends React.Component {
        onItemChange = (itemInEdit) => {
            this.setState({
                itemInEdit
            });
        }
        ...
    }
In this article
 /