Using a Custom Form Editor for Scheduler in NetSuite

1 Answer 131 Views
Editor Scheduler
Neil
Top achievements
Rank 1
Neil asked on 27 Jan 2023, 08:36 PM

Hi!

We are trying to customize the scheduler form editor, but the field is not showing up. Any ideas why? Screenshots of the SchedulerForm's editor and what we see in the UI below:

 

What we see: (text area input doesn't show up):
*note that we have tried other field types (e.g. dropdown and datepicker) with similar results

 

Thank you!

Neil
Top achievements
Rank 1
commented on 27 Jan 2023, 08:52 PM | edited

Script below (note we are using a cdn only method highlighted in this post):

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width">
    <title>KendoReact</title>
    <script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/axios/1.2.2/axios.min.js"></script>
    <script src="https://unpkg.com/react@18/umd/react.production.min.js" crossorigin></script>
    <script src="https://unpkg.com/react-dom@18/umd/react-dom.production.min.js" crossorigin></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/prop-types/15.7.2/prop-types.min.js"></script>
    <script src="https://unpkg.com/@progress/kendo-react-common/dist/cdn/js/kendo-react-common.js"></script>
    <script src="https://unpkg.com/@progress/kendo-date-math/dist/cdn/js/kendo-date-math.js"></script>
    <script src="https://unpkg.com/@progress/kendo-drawing/dist/cdn/js/kendo-drawing.js"></script>
    <script src="https://unpkg.com/@progress/kendo-licensing/dist/index.js"></script>
    <script>
        KendoLicensing.setScriptKey(
            'xxx' +
            'yyy' +
            'zzz' +
            '000'
        );
    </script>
    <script src="https://unpkg.com/@progress/kendo-react-intl/dist/cdn/js/kendo-react-intl.js"></script>
    <script src="https://unpkg.com/@progress/kendo-react-all/dist/cdn/js/kendo-react-all.js"></script>
    <script src="https://unpkg.com/@progress/kendo-react-scheduler/dist/cdn/js/kendo-react-scheduler.js"></script>
    <script src="https://unpkg.com/@progress/kendo-react-dropdowns/dist/cdn/js/kendo-react-dropdowns.js"></script>
    <script src="https://unpkg.com/@progress/kendo-react-form/dist/cdn/js/kendo-react-form.js"></script>
    <script src="https://unpkg.com/@progress/kendo-react-labels/dist/cdn/js/kendo-react-labels.js"></script>
    <script src="https://unpkg.com/@progress/kendo-react-inputs/dist/cdn/js/kendo-react-inputs.js"></script>
    <script src="https://unpkg.com/@progress/kendo-react-dateinputs/dist/cdn/js/kendo-react-dateinputs.js"></script>
    <script src="https://unpkg.com/@progress/kendo-react-dialogs/dist/cdn/js/kendo-react-dialogs.js"></script>
 
    <link rel="stylesheet" href="https://unpkg.com/@progress/kendo-theme-default@latest/dist/all.css"></link>
    <!--link rel="stylesheet" href="https://kendo.cdn.telerik.com/themes/5.8.0/default/default-ocean-blue.css"></link-->
    <!--link rel="stylesheet" href="https://unpkg.com/@progress/kendo-theme-material/dist/all.css"></link-->
    <link rel="stylesheet" href="https://cdn.kendostatic.com/themes/6.0.3/default/default-ocean-blue.css"></link>
    <link href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" rel="stylesheet"
        integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
    <style>
        body {
            position: relative;
        }
   
        html,
        body {
            height: 100%;
        }
   
        my-app {
            display: block;
            width: 100%;
            height: 100%;
            overflow: auto;
            min-height: 800px;
            box-sizing: border-box;
            padding: 30px;
        }
   
        @keyframes k-loading-animation {
            0% {
                transform: rotate(0deg);
            }
   
            100% {
                transform: rotate(360deg);
            }
        }
   
        .k-i-loading.k-example-loading {
            font-size: 64px;
            position: absolute;
            top: 50%;
            left: 50%;
            transform: translate(-50%, -50%);
            color: rgb(144, 152, 165);
        }
   
        .k-i-loading.k-example-loading::before,
        .k-i-loading.k-example-loading::after {
            position: absolute;
            top: 50%;
            left: 50%;
            display: inline-block;
            content: "";
            box-sizing: inherit;
            border-radius: 50%;
            border-width: .05em;
            border-style: solid;
            border-color: currentColor;
            border-top-color: transparent;
            border-bottom-color: transparent;
            background-color: transparent;
        }
   
        .k-icon.k-i-loading.k-example-loading::before,
        .k-icon.k-i-loading::after {
            content: "";
        }
   
        .k-i-loading.k-example-loading::before {
            margin-top: -0.5em;
            margin-left: -0.5em;
            width: 1em;
            height: 1em;
            animation: k-loading-animation .7s linear infinite;
        }
   
        .k-i-loading.k-example-loading::after {
            margin-top: -0.25em;
            margin-left: -0.25em;
            width: .5em;
            height: .5em;
            animation: k-loading-animation reverse 1.4s linear infinite;
        }
   
        .example-wrapper {
            min-height: 280px;
            align-content: flex-start;
        }
   
        .example-wrapper p,
        .example-col p {
            margin: 20px 0 10px;
        }
   
        .example-wrapper p:first-child,
        .example-col p:first-child {
            margin-top: 0;
        }
   
        .example-col {
            display: inline-block;
            vertical-align: top;
            padding-right: 20px;
            padding-bottom: 20px;
        }
   
        .example-config {
            margin: 0 0 20px;
            padding: 20px;
            background-color: rgba(0, 0, 0, .03);
            border: 1px solid rgba(0, 0, 0, .08);
        }
   
        .event-log {
            margin: 0;
            padding: 0;
            max-height: 100px;
            overflow-y: auto;
            list-style-type: none;
            border: 1px solid rgba(0, 0, 0, .08);
            background-color: white;
        }
   
        .event-log li {
            margin: 0;
            padding: .3em;
            line-height: 1.2em;
            border-bottom: 1px solid rgba(0, 0, 0, .08);
        }
   
        .event-log li:last-child {
            margin-bottom: -1px;
        }
    </style>
</head>
<body>
    <my-app>
        <span class="k-icon k-i-loading"></span>
    </my-app>
</body>
<script type="text/babel">
    const baseDataSet = '[baseDataSet]';
    const baseData = JSON.parse(baseDataSet);
    console.log(baseData);
        /*[{
            "TaskID": 119,
            "OwnerID": 3,
            "Title": "Helpdesk weekly meeting",
            "Description": "",
            "StartTimezone": null,
            "Start": "2013-12-05T15:00:00.000Z",
            "End": "2013-12-05T16:00:00.000Z",
            "EndTimezone": null,
            "RecurrenceRule": "FREQ=WEEKLY;BYDAY=WE",
            "RecurrenceID": null,
            "RecurrenceException": null,
            "isAllDay": false
        }, {
            "TaskID": 120,
            "OwnerID": 3,
            "Title": "Website upload",
            "Description": "",
            "StartTimezone": null,
            "Start": "2013-12-07T07:00:00.000Z",
            "End": "2013-12-07T08:30:00.000Z",
            "EndTimezone": null,
            "RecurrenceRule": "",
            "RecurrenceID": null,
            "RecurrenceException": null,
            "isAllDay": false
        }];*/
        const customModelFields = {
            id: 'TaskID',
            title: 'Title',
            description: 'Description',
            start: 'Start',
            end: 'End',
            recurrenceRule: 'RecurrenceRule',
            recurrenceId: 'RecurrenceID',
            recurrenceExceptions: 'RecurrenceException'
        };
        const currentYear = new Date().getFullYear();
        const parseAdjust = eventDate => {
            const date = new Date(eventDate);
            date.setFullYear(currentYear);
            return date;
        };
        const randomInt = (min, max) => Math.floor(Math.random() * (max - min + 1)) + min;
        const displayDate = new Date();
        //const displayDate = new Date(Date.UTC(currentYear, 5, 24));
        const sampleData = baseData.map(dataItem => ({
            id: dataItem.TaskID,
            start: parseAdjust(dataItem.Start),
            startTimezone: dataItem.startTimezone,
            end: parseAdjust(dataItem.End),
            endTimezone: dataItem.endTimezone,
            isAllDay: dataItem.isAllDay,
            title: dataItem.Title,
            description: dataItem.Description,
            recurrenceRule: dataItem.RecurrenceRule,
            recurrenceId: dataItem.RecurrenceID,
            recurrenceExceptions: dataItem.RecurrenceException,
            roomId: dataItem.RoomID,
            ownerID: dataItem.OwnerID,
            personId: dataItem.OwnerID
        }));        
        const sampleDataWithResources = baseData.map(dataItem => ({
            id: dataItem.TaskID,
            start: parseAdjust(dataItem.Start),
            startTimezone: dataItem.startTimezone,
            end: parseAdjust(dataItem.End),
            endTimezone: dataItem.endTimezone,
            isAllDay: dataItem.isAllDay,
            title: dataItem.Title,
            description: dataItem.Description,
            recurrenceRule: dataItem.RecurrenceRule,
            recurrenceId: dataItem.RecurrenceID,
            recurrenceExceptions: dataItem.RecurrenceException,
            roomId: randomInt(1, 2),
            personId: randomInt(1, 2)
        }));
        const sampleDataWithCustomSchema = baseData.map(dataItem => ({
            ...dataItem,
            Start: parseAdjust(dataItem.Start),
            End: parseAdjust(dataItem.End),
            PersonIDs: randomInt(1, 2),
            RoomID: randomInt(1, 2)
        }));
        console.log(sampleDataWithCustomSchema);
       
   const App = () => {
        console.log(window);
        const Scheduler = window.KendoReactScheduler.Scheduler
        const SchedulerForm = window.KendoReactScheduler.SchedulerForm
        const SchedulerFormEditor = window.KendoReactScheduler.SchedulerFormEditor
        const AgendaView = window.KendoReactScheduler.AgendaView
        const TimelineView = window.KendoReactScheduler.TimelineView
        const DayView = window.KendoReactScheduler.DayView
        const WeekView = window.KendoReactScheduler.WeekView
        const MonthView = window.KendoReactScheduler.MonthView
        const timezoneNames = window.KendoDateMath.timezoneNames
        const DropDownList = window.KendoReactDropdowns.DropDownList
        const guid = window.KendoReactCommon.guid
        const FormElement = window.KendoReactForm.FormElement
        const Field = window.KendoReactForm.Field
        const Label = window.KendoReactLabels.Label
        const Error = window.KendoReactLabels.Error
        const TextArea = window.KendoReactInputs.TextArea
        const DatePicker = window.KendoReactDateinputs.DatePicker
        const DateTimePicker = window.KendoReactDateinputs.DateTimePicker
        const Dialog = window.KendoReactDialogs.Dialog
       
        const [view, setView] = React.useState("month");
        const [date, setDate] = React.useState(displayDate);
        const [timezone] = React.useState("Etc/UTC");
        const [orientation] = React.useState("horizontal");
        const [data, setData] = React.useState(sampleDataWithCustomSchema);
        const handleViewChange = React.useCallback(
            (event) => {
            setView(event.value);
            },
            [setView]
        );
        const handleDateChange = React.useCallback(
            (event) => {
            setDate(event.value);
            },
            [setDate]
        );
        const handleDataChange = React.useCallback(
        ({ created, updated, deleted }) => {
           
            for(var projTask of updated) {
                axios.post(`https://tstdrv1967913.app.netsuite.com/app/site/hosting/scriptlet.nl?script=2165&deploy=1&recordaction=update&firstParam=${projTask.TaskID}`,
                    {
                        firstName: 'first',
                        lastName: 'last'
                    }
                ).then(
                    (response) => {
                        setData((old) =>
                            old.map(
                                (item) =>
                                updated.find((current) => current.TaskID === item.TaskID) || item
                            )
                        )
                    }
                );
            }
            for(var projTask of created) {
                axios.post(`https://tstdrv1967913.app.netsuite.com/app/site/hosting/scriptlet.nl?script=2165&deploy=1&recordaction=create&firstParam=${projTask.TaskID}`,
                    {
                        firstName: 'first',
                        lastName: 'last'
                    }
                ).then(
                    (response) => {
                        console.log(response.data.id);
                        setData((old) =>
                            old.concat(
                                created.map((item) =>
                                    Object.assign({}, item, {
                                        //TaskID: guid()  
                                        TaskID: response.data.id
                                    })
                                )
                            )
                        );
                    }
                );
            }
            },
            [setData]
        );
        // Custom Form - START
        const teammembers = [{
            value: 1,
            text: 'Erwin'
        }, {
            value: 2,
            text: 'Don'
        }, {
            value: 3,
            text: 'Neil'
        }];
        const AssignedToEditor = props => {
            const handleChange = event => {
                if (props.onChange) {
                props.onChange.call(undefined, {
                    value: event.value.value
                });
                }
            };
            return <DropDownList onChange={handleChange} value={teammembers.find(t => t.value === props.value)} data={teammembers} dataItemKey={'value'} textField={'text'} />;
        };
        const CustomDialog = props => {
            return <Dialog {...props} title={'Project Action'} />;
        };
        const CustomFormEditor = (props) => {
            return (
                <FormElement horizontal={true}>
                <div className="k-form-field">
                    <Label>Notes</Label>
                    <div className="k-form-field-wrap">
                    <Field name={"Notes"} component={TextArea} rows={1} />
                    </div>
                </div>
                </FormElement>
            );
        };
        const FormWithCustomEditor = props => {
            const requiredValidator = React.useCallback(value => value === undefined || value === null || value === '' ? 'Field is required.' : undefined, []);
            const formValidator = (_dataItem, formValueGetter) => {
                let result = {};
                //result.Patient = [requiredValidator(formValueGetter('Patient'))].filter(Boolean).reduce((current, acc) => current || acc, '');
                //result.Treatment = [requiredValidator(formValueGetter('Treatment'))].filter(Boolean).reduce((current, acc) => current || acc, '');
                return result;
            };
            return <SchedulerForm
                {...props}
                editor={CustomFormEditor}
                dialog={CustomDialog}
                validator={formValidator}
            />;
        };
        // Custom Form - END
        return (
            <div>
                <div className="example-config">Hello</div>
                <Scheduler
                    data={data}
                    onDataChange={handleDataChange}
                    view={view}
                    onViewChange={handleViewChange}
                    date={date}
                    onDateChange={handleDateChange}
                    editable={true}
                    timezone={timezone}
                    modelFields={customModelFields}
                    group={{
                    orientation
                    }}
                    height={900}
                    form={FormWithCustomEditor}
                >
                    <TimelineView title="TimeTime" />
                    <DayView />
                    <WeekView />
                    <MonthView />
                </Scheduler>
            </div>
        );
    };
    ReactDOM.render(<App />, document.querySelector('my-app'));
</script>
</html>

1 Answer, 1 is accepted

Sort by
0
Konstantin Dikov
Telerik team
answered on 31 Jan 2023, 01:27 PM

Hello Neil,

I have tried the custom form editor from the code snippet that you have shared, but everything is rendered and displayed correctly in the example:

If the issue on your side persists, please try to isolate the problem in a stackblitz example that we can test and debug locally.

 

Regards,
Konstantin Dikov
Progress Telerik

Virtual Classroom, the free self-paced technical training that gets you up to speed with Telerik and Kendo UI products quickly just got a fresh new look + new and improved content including a brand new Blazor course! Check it out at https://learn.telerik.com/.

Tags
Editor Scheduler
Asked by
Neil
Top achievements
Rank 1
Answers by
Konstantin Dikov
Telerik team
Share this question
or