SchedulerEditItem

The SchedulerEditItem component is responsible for the editing functionality of an Item.

To extend the default SchedulerEditItem, set the editItem property to either the Scheduler or a specific view, to a modified version of the SchedulerEditItem component.

Controlling the Editing

The SchedulerEditItem exposes the following properties to allow controlling the internal edit state.

To control the state of any of the state fields, provide the corresponding value-handler pair. For example, if you want to control the dragItem, provide your own onDragItemChange handler, modify the DataItem as needed, and pass it back through the dragItem property.

The following example demonstrates controlling the dragItem state to disallow dragging outside of working hours. We will be hard-coding the timezone to the Etc/UTC standard.

import React from 'react';
import ReactDOM from 'react-dom';
import {
    Scheduler,
    WeekView,

    SchedulerEditItem
} from '@progress/kendo-react-scheduler';

const sampleData = [{
    id: 0,
    title: 'Team Meeting',
    start: new Date("2020-01-23T09:30:00.000Z"),
    end: new Date("2020-01-23T10:30:00.000Z")
}]
const displayDate = new Date("2020-01-23T09:30:00.000Z");

const CustomEditItem = (props) => {
    const [dragItem, setDragItem] = React.useState(null);

    const handleDragItemChange = (event) => {
        const minWorkHour = new Date("2020-01-23T08:00:00.000Z").getUTCHours();
        const maxWorkHour = new Date("2020-01-23T17:00:00.000Z").getUTCHours();
        const minWorkDate = new Date("2020-01-20T00:00:00.000Z").getUTCDate();
        const maxWorkDate = new Date("2020-01-24T00:00:00.000Z").getUTCDate();

        if (
            event.value === null
            || (minWorkHour <= event.value.start.getUTCHours()
                && event.value.end.getUTCHours() < maxWorkHour
                && minWorkDate <= event.value.start.getUTCDate()
                && event.value.start.getUTCDate() <= maxWorkDate)
        ) {
            setDragItem(event.value)
        }
    }

    return (
        <SchedulerEditItem
            {...props}
            dragItem={dragItem}
            onDragItemChange={handleDragItemChange}
        />)
}

const App = () => {
    return (
        <Scheduler
            timezone="Etc/UTC"
            data={sampleData}
            defaultDate={displayDate}
            editItem={CustomEditItem}
            editable={{ drag: true }}
        >
            <WeekView showWorkHours={false} startTime="06:00" />
        </Scheduler>
    );
};

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

Extending the Editing

The most common scenario of controlling the editing is to build on top of it. Adding additional functionality without modifying the current one is possible by controlling the state, but do not override the current state.

In the following example we will create an additional step before entering form-edit mode. The requirements are:

  • On click, display a custom Popup with additional info and a close button and an expand button.
  • On close button click, close the popup.
  • On expand button click, change the formItem state of the SchedulerEditItem.

First, we will define our custom SchedulerEditItem which will contain our logic.

const CustomEditItem = (props) => {
    return (<SchedulerEditItem {...props} />)
}

Now we'd like to render a Popup, whenever the item receives a focus.

const CustomEditItem = (props) => {
    const [show, setShow] = React.useState(false);

    const handleFocus = React.useCallback(
        (event) => { setShow(true); if(props.onFocus) {props.onFocus(event)} },
        [setShow]
    )

    return (
        <React.Fragment>
            <SchedulerEditItem
                {...props}
                onFocus={handleFocus}
            />
            <Popup
                show={show}
            >
                <div>
                    <h5>{props.title}</h5>
                    <button className="k-icon k-i-edit"/>
                    <button className="k-icon k-i-close"/>
                </div>
            </Popup>
        </React.Fragment>
    )
}

The popup needs an anchor, so we will need the ref from the default item.

const CustomEditItem = (props) => {
    const ref = React.useRef(null);
    const [show, setShow] = React.useState(false);

    const handleFocus = React.useCallback(
        (event) => { setShow(true); if(props.onFocus) {props.onFocus(event)} },
        [setShow]
    )

    return (
        <React.Fragment>
            <SchedulerEditItem
                ref={ref}
                {...props}
                onFocus={handleFocus}
            />
            <Popup
                anchor={ref.current && ref.current.element}
                show={show}
            >
                <div>
                    <h5>{props.title}</h5>
                    <button className="k-icon k-i-edit"/>
                    <button className="k-icon k-i-close"/>
                </div>
            </Popup>
        </React.Fragment>
    )
}

Adding the handler to handle the close click and the edit click, as well as controlling the formItem state, while still accepting any change to it proposed by the SchedulerItem through the onEditItemChange event.

const CustomEditItem = (props) => {
    const ref = React.useRef(null);

    const [show, setShow] = React.useState(false);
    const [formItem, setFormItem] = React.useState(null);

    const handleFocus = React.useCallback(
        (event) => { setShow(true); if(props.onFocus) {props.onFocus(event)} },
        [setShow]
    )

    const handleCloseClick = React.useCallback(
        (event) => { setShow(false); },
        [setShow]
    )

    const handleEditClick = React.useCallback(
        (event) => { setFormItem(props.dataItem); },
        [setShow]
    )

    const handleFormItemChange = React.useCallback(
        (event) => { setFormItem(event.value); },
        [setShow]
    )

    return (
        <React.Fragment>
            <SchedulerEditItem
                ref={ref}
                {...props}
                onFocus={handleFocus}
                formItem={formItem}
                onFormItemChange={handleFormItemChange}
            />
            <Popup
                anchor={ref.current && ref.current.element}
                show={show}
            >
                <div>
                    <h5>{props.title}</h5>
                    <button className="k-icon k-i-edit" onClick={handleEditClick} />
                    <button className="k-icon k-i-close" onClick={handleCloseClick} />
                </div>
            </Popup>
        </React.Fragment>
    )
}

Now lets pass the CustomEditItem to the Scheduler and see our example in action:

import React from 'react';
import ReactDOM from 'react-dom';
import {
    Scheduler,
    WeekView,

    SchedulerEditItem
} from '@progress/kendo-react-scheduler';
import { Popup } from '@progress/kendo-react-popup';

const sampleData = [{
    id: 0,
    title: 'Team Meeting',
    start: new Date("2020-01-23T09:30:00.000Z"),
    end: new Date("2020-01-23T10:30:00.000Z")
}]
const displayDate = new Date("2020-01-23T09:30:00.000Z");

const CustomEditItem = (props) => {
    const ref = React.useRef(null);

    const [show, setShow] = React.useState(false);
    const [formItem, setFormItem] = React.useState(null);

    const handleFocus = React.useCallback(
        (event) => { console.log(ref); setShow(true); if (props.onFocus) { props.onFocus(event) } },
        [setShow]
    )

    const handleCloseClick = React.useCallback(
        (event) => { setShow(false); },
        [setShow]
    )

    const handleEditClick = React.useCallback(
        (event) => { setFormItem(props.dataItem); setShow(false); },
        [setShow]
    )

    const handleFormItemChange = React.useCallback(
        (event) => { setFormItem(event.value); },
        [setShow]
    )

    return (
        <React.Fragment>
            <SchedulerEditItem
                ref={ref}
                {...props}
                onFocus={handleFocus}
                formItem={formItem}
                onFormItemChange={handleFormItemChange}
            />
            <Popup
                anchor={ref.current && ref.current.element}
                show={show}
            >
                <div className="p-1">
                    <h5>{props.title}</h5>
                    <a className="k-icon k-i-edit" onClick={handleEditClick} />
                    <a className="k-icon k-i-close" onClick={handleCloseClick} />
                </div>
            </Popup>
        </React.Fragment>
    )
}

const App = () => {
    return (
        <Scheduler
            timezone="Etc/UTC"
            data={sampleData}
            defaultDate={displayDate}
            editItem={CustomEditItem}
            editable={{ edit: true }}
        >
            <WeekView />
        </Scheduler>
    );
};

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