External Form

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

import React from 'react';
import ReactDOM from 'react-dom';
import { Grid, GridColumn as Column, GridToolbar } from '@progress/kendo-react-grid';
import { sampleProducts } from './sample-products.jsx';
import DialogContainer from './DialogContainer.jsx';
import cellWithEditing from './cellWithEditing.jsx';

class App extends React.Component {
    state = {
        products: sampleProducts.slice(0, 7),
        productInEdit: undefined
    };

    edit = (dataItem) => {
        this.setState({ productInEdit: this.cloneProduct(dataItem) });
    }

    remove = (dataItem) => {
        const products = this.state.products.slice();
        const index = products.findIndex(p => p.ProductID === dataItem.ProductID);
        if (index !== -1) {
            products.splice(index, 1);
            this.setState({
                products: products
            });
        }
    }

    save = () => {
        const dataItem = this.state.productInEdit;
        const products = this.state.products.slice();

        if (dataItem.ProductID === undefined) {
            products.unshift(this.newProduct(dataItem));
        } else {
            const index = products.findIndex(p => p.ProductID === dataItem.ProductID);
            products.splice(index, 1, dataItem);
        }

        this.setState({
            products: products,
            productInEdit: undefined
        });
    }

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

    insert = () => {
        this.setState({ productInEdit: { } });
    }

    render() {
        return (
            <div >
                <Grid
                    data={this.state.products}
                    style={{ height: '420px' }}
                >
                    <GridToolbar>
                        <button
                            onClick={this.insert}
                            className="k-button"
                        >
                            Add New
                        </button>
                    </GridToolbar>
                    <Column field="ProductID" title="Id" width="50px" />
                    <Column field="ProductName" title="Product Name" />
                    <Column field="UnitsInStock" title="Units In Stock" />
                    <Column field="Discontinued" />
                    <Column
                        title="Edit"
                        cell={cellWithEditing(this.edit, this.remove)}
                    />
                </Grid>
                {this.state.productInEdit && <DialogContainer dataItem={this.state.productInEdit} save={this.save} cancel={this.cancel}/>}
            </div>
        );
    }

    dialogTitle() {
        return `${this.state.productInEdit.ProductID === undefined ? 'Add' : 'Edit'} product`;
    }
    cloneProduct(product) {
        return Object.assign({}, product);
    }

    newProduct(source) {
        const newProduct = {
            ProductID: this.generateId(),
            ProductName: '',
            UnitsInStock: 0,
            Discontinued: false
        };

        return Object.assign(newProduct, source);
    }

    generateId() {
        let id = 1;
        this.state.products.forEach(p => { id = Math.max((p.ProductID || 0) + 1, id); });
        return 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 Grid.

  1. When a record is in edit mode, show the container and pass the edited item to the DialogContainer component.

    {this.state.productInEdit &&
        <DialogContainer dataItem={this.state.productInEdit} save={this.save} cancel={this.cancel}/>}
  2. Inside DialogContainer, bind the editors to the value of the row data.

    <form onSubmit={this.handleSubmit}>
        <div style={{ marginBottom: '1rem' }}>
            <label>
            Product Name<br />
            <Input
                type="text"
                name="ProductName"
                value={this.state.productInEdit.ProductName || ''}
                onChange={this.onDialogInputChange}
            />
            </label>
        </div>
        <div style={{ marginBottom: '1rem' }}>
            <label>
            Units In Stock<br />
            <NumericTextBox
                name="UnitsInStock"
                value={this.state.productInEdit.UnitsInStock || 0}
                onChange={this.onDialogInputChange}
            />
            </label>
        </div>
        <div>
            <label>
            <input
                type="checkbox"
                name="Discontinued"
                checked={this.state.productInEdit.Discontinued || false}
                onChange={this.onDialogInputChange}
            />
            Discontinued product
                            </label>
        </div>
    </form>
  3. Handle the change events of the editors.

    onDialogInputChange = (event) => {
        let target = event.target;
        const value = target.type === 'checkbox' ? target.checked : target.value;
        const name = target.props ? target.props.name : target.name;
    
        const edited = this.state.productInEdit;
        edited[name] = value;
    
        this.setState({
            productInEdit: edited
        });
    }
  4. To improve its performance, the Grid refreshes its data on each Update button click. To update the Grid on type, directly update the data state of the Grid on change.

In this article
 /