Hi there,
I have a custom EditorTemplate and custom Popup Footer that I am trying to get working and I am slightly confused about the use of addEvent, saveEvent and deleteEvent. How do I ensure that my state is updated upon changing an input? Or deleting an event? Sometimes it seems as though my data persists, and other times it doesn't. The below code works for a saveEvent, but my add and delete events in my custom Popup Footer does not. Also, do I need to manually update my state as I am doing below?
If you do send an example via StackBlitz, please create it using React Functional Components.
Save Event
Add and Delete in Custom Popup Footer
Thank you.
Hi - Are you able to provide an update/solution?
Additionally, are you able to provide a custom Editor Template sample using React Functional Components? I am having a difficult time figuring out how to update inputs in my custom Editor Template and have the changes persist to my local data. Please advise.
Thank you.
Hi Jessica,
Q1: How do I ensure that my state is updated upon changing an input? Or deleting an event? Sometimes it seems as though my data persists, and other times it doesn't. The below code works for a saveEvent, but my add and delete events in my custom Popup Footer does not. Also, do I need to manually update my state as I am doing below?
Demo: https://ej2.syncfusion.com/react/demos/#/material/schedule/quick-info-template
UG: https://ej2.syncfusion.com/react/documentation/schedule/editor-template#customizing-quick-popups
You can perform CRUD actions with the Schedule using the quickInfoTemplates and editorTemplate with the state as shown in the below code snippet with help of the actionBegin event of the Schedule.
[App.js]
function App() { let scheduleObj; let dateRange = {}; let quickPopupData = {}; const [scheduleModel, setScheduleModel] = useState({ currentAction: "InitialRendering", currentView: "Week", selectedDate: new Date(2021, 1, 15), dataSource: getCurrentViewApps(new Date(2021, 1, 15), "Week", true) });
function headerTemplate(props) { return <HeaderTemplate data={props}></HeaderTemplate> }
function contentTemplate(props) { return <ContentTemplate data={props} handleChange={handleTextChange}></ContentTemplate> }
function footerTemplate(props) { return <FooterTemplate data={props} getQuickData={getQuickPopupData} scheduleObj={scheduleObj}></FooterTemplate>; }
function handleTextChange(quickData) { quickPopupData = quickData; }
function getQuickPopupData() { return quickPopupData; }
function editorTemplate(props) { return <EditorTemplate data={props}></EditorTemplate>; }
function onActionBegin(args) { if (["eventCreate", "eventChange", "eventRemove"].indexOf(args.requestType) > -1) { // Prevent the default CRUD action by setting up true args.cancel = true; let resultData = extend([], scheduleModel.dataSource, null, true); if (args.addedRecords.length > 0) { // Adding appointment resultData = resultData.concat(args.addedRecords); } if (args.changedRecords.length > 0) { for (let i = 0; i < args.changedRecords.length; i++) { const index = resultData.findIndex((data) => { return data.Id === args.changedRecords[i].Id }); // Updating appointment resultData[index] = args.changedRecords[i]; } } if (args.deletedRecords.length > 0) { for (let i = 0; i < args.deletedRecords.length; i++) { const index = resultData.findIndex((data) => { return data.Id === args.deletedRecords[i].Id }); // Deleting appointment resultData.splice(index, 1); } } // Update the state with the new data setScheduleModel(prevState => ({ ...prevState, dataSource: resultData })); } }
return ( <div className="App"> <ScheduleComponent width='100%' height='650px' ref={t => scheduleObj = t} selectedDate={scheduleModel.selectedDate} currentView={scheduleModel.currentView} eventSettings={{ dataSource: scheduleModel.dataSource }} quickInfoTemplates={{ header: headerTemplate.bind(this), content: contentTemplate.bind(this), footer: footerTemplate.bind(this) }} editorTemplate={editorTemplate.bind(this)} actionBegin={onActionBegin.bind(this)} navigating={onNavigating.bind(this)}> </ScheduleComponent> </div> ); }
export default App; |
When a new appointment is added through the addEvent method and an appointment deleted event deleteEvent method as shown in the below code snippet. You can update the state in the actionBegin event of the Schedule as shown in the above code snippet. For editorTemplate while clicking the Save, or Delete button the actionBegin method is automatically triggered or you can use the addEvent, saveEvent, and deleteEvent methods of the Schedule. So, you can update the state as in the above code snippet.
[footer-template.js]
function FooterTemplate(props) {
function buttonClickActions(e) { var appDetail = props.getQuickData(); var scheduleObj = props.scheduleObj; const getSlotData = () => { const addObj = {}; addObj.Id = scheduleObj.getEventMaxID(); addObj.Subject = appDetail && appDetail.Subject ? appDetail.Subject : 'Add title'; addObj.StartTime = new Date(scheduleObj.activeCellsData.startTime); addObj.EndTime = new Date(scheduleObj.activeCellsData.endTime); addObj.IsAllDay = scheduleObj.activeCellsData.isAllDay; addObj.Description = appDetail && appDetail.Description ? appDetail.Description : 'Add notes'; return addObj; }; if (e.target.id === 'add') { const addObj = getSlotData(); props.scheduleObj.addEvent(addObj); } else if (e.target.id === 'delete') { const eventDetails = scheduleObj.activeEventData.event; let currentAction = 'Delete'; if (eventDetails.RecurrenceRule) { currentAction = 'DeleteOccurrence'; } scheduleObj.deleteEvent(eventDetails, currentAction); } else { const isCellPopup = props.data.elementType === "cell"; const eventDetails = isCellPopup ? getSlotData() : scheduleObj.activeEventData.event; let currentAction = isCellPopup ? 'Add' : 'Save'; if (eventDetails.RecurrenceRule) { currentAction = 'EditOccurrence'; } scheduleObj.openEditor(eventDetails, currentAction, true); } scheduleObj.closeQuickInfoPopup(); };
return ( <div className="quick-info-footer"> {props.data.elementType === "cell" ? <div className="cell-footer"> <ButtonComponent id="more-details" cssClass='e-flat' content="More Details" onClick={buttonClickActions} /> <ButtonComponent id="add" cssClass='e-flat' content="Add" isPrimary={true} onClick={buttonClickActions} /> </div> : <div className="event-footer"> <ButtonComponent id="delete" cssClass='e-flat' content="Delete" onClick={buttonClickActions} /> <ButtonComponent id="more-details" cssClass='e-flat' content="More Details" isPrimary={true} onClick={buttonClickActions} /> </div>} </div> ); }; export default FooterTemplate; |
Q2: a custom Editor Template sample using React Functional Components?
Demo: https://ej2.syncfusion.com/react/demos/#/material/schedule/editor-template
You can use the custom editorTemplate with the Schedule as shown in the below code snippet. If you want the Schedule automatically recognize all the input fields and get the value from each inputs fields and form an appointment object while saving an appointment you need to add the “e-field” class and “name” attributes to each input element.
[App.js]
import EditorTemplate from './editor-template';
function App() { function editorTemplate(props) { return <EditorTemplate data={props}></EditorTemplate>; }
return ( <div className="App"> <ScheduleComponent editorTemplate={editorTemplate.bind(this)}> </ScheduleComponent> </div> ); }
export default App; |
[editor-template.js]
import React, { useState } from 'react'; import { DateTimePickerComponent } from '@syncfusion/ej2-react-calendars'; import { DropDownListComponent } from '@syncfusion/ej2-react-dropdowns';
function EditorTemplate(props) { let data = props?.data; const [subject, setSubject] = useState(data?.Subject); const [description, setDescription] = useState(data?.Description);
return ( (data !== undefined) ? <table className="custom-event-editor" style={{ width: '100%' }} cellPadding={5}> <tbody> <tr> <td className="e-textlabel">Summary</td> <td colSpan={4}> <input id="Summary" className="e-field e-input" type="text" data-name="Subject" value={subject} style={{ width: '100%' }} onChange={(args) => { setSubject(args.target.value) }} /> </td> </tr> <tr> <td className="e-textlabel">Status</td><td colSpan={4}> <DropDownListComponent id="EventType" placeholder='Choose status' data-name='EventType' value={data.EventType} className="e-field" style={{ width: '100%' }} dataSource={['New', 'Requested', 'Confirmed']}> </DropDownListComponent> </td> </tr> <tr> <td className="e-textlabel">From</td> <td colSpan={4}> <DateTimePickerComponent id="StartTime" format='dd/MM/yy hh:mm a' data-name="StartTime" value={new Date(data.startTime || data.StartTime)} className="e-field"></DateTimePickerComponent> </td> </tr> <tr> <td className="e-textlabel">To</td> <td colSpan={4}> <DateTimePickerComponent id="EndTime" format='dd/MM/yy hh:mm a' data-name="EndTime" value={new Date(data.endTime || data.EndTime)} className="e-field"></DateTimePickerComponent> </td> </tr> <tr> <td className="e-textlabel">Reason</td> <td colSpan={4}> <textarea id="Description" className="e-field e-input" name="Description" value={description} onChange={(args) => { setDescription(args.target.value) }}></textarea> </td> </tr> </tbody> </table> : <div></div> ); };
export default EditorTemplate; |
Regards,
Ravikumar Venkatesan
Thank you! This is tremendously helpful. One more question.
Jessica,
We checked your shared codes at our end. We suspect that the Schedule is fully rerendered or refreshed while the state update is performed on the actionBegin event of the Schedule or any of the sample end customizations causing your reported behavior. So, if you still facing the same behavior share the below details to proceed further.
Hi,
Yes, that is correct. Upon an update occurring in the custom editor template or the custom quick pop up, the Schedule component is rerendered and the current display time always resets to 9am. I am not comfortable sharing my entire codebase in a public forum, but do not know how to replicate the issue on your end since I do not know what causes it. If possible, are you able to provide a few reasons that could cause the component to re-render this way? I have copied the code you provided above almost verbatim in my application, so not much is different.
Additionally, is it possible to use Material UI components in tandem with Syncfusion schedule? I originally was using Material UI inputs on my editor template, but could not get the schedule functionality to work which is why I changed to using Syncfusion components.
Thanks in advance.
Hi Jessica,
We have created a new ticket under your account to follow up on your query. We suggest you follow up with the ticket for further updates. Please log in using the below link.
https://support.syncfusion.com/support
Regards,
Ravikumar Venkatesan