Our powerful JS Calendar component


Post by bin_yu »

Hi All,

I am using Calendar as a pluggable widgets of Mendix, so I want to call Mendix API in the CustomCalendar.tsx file to save Calendar model data into DB

I found a function onAfterEventSave(in the BryntumCalendarProps config type) where I can handle events after saving, but it seemed that I am not able to call the mendix API in CalendarConfig.ts file.

Therefore, after clicking save in the editor below,

save hanld.png
save hanld.png (187.55 KiB) Viewed 398 times

is there any method to save the data in the CustomCalendar.tsx file so that I can save data to the DB.

CustomCalendar.tsx file

import { createElement, Fragment, ReactElement, useRef, useState, useMemo } from 'react';
import {
    BryntumCalendarProjectModel, BryntumCalendar,

} from '@bryntum/calendar-react';
import {
    calendarProps,
} from './components/CalendarConfig';
import { CustomCalendarContainerProps } from "../typings/CustomCalendarProps";
import { projectData } from './components/AppData';
import { ObjectItem, ValueStatus } from "mendix";
import './ui/CustomCalendar.scss';
import {
    DateHelper,
    ResourceModel,
    TimeRangeModelConfig
    //, Toolbar 
} from '@bryntum/calendar';

const mapMxID = (mxID: string | Big | undefined): string | undefined =>
    mxID ? (typeof mxID === "string" ? mxID : mxID.toString()) : undefined;

export interface ITask {
    obj: ObjectItem;
    id: string;
    projectId: string;
    projectName: string;
    progress: number | undefined,
    hour: number | undefined,
    message: string,
    actualStart: Date | undefined
    name: string | undefined;
    startDate: Date | undefined;
    endDate: Date | undefined;
    planworktime: number;
    resourceId: string,
    eventColor: string
}

export interface IResource {
    obj: ObjectItem;
    id: string;
    resourceName: string | undefined;
    resourceRole: string | undefined;
}

function formatDate2(date: string | Date | undefined): string {
    if (!date || date === undefined) return '';
    if (typeof date === 'string') {
        const dateObj = new Date(date);
        return DateHelper.format(dateObj, 'YYYY-MM-DD');
    }
    
return DateHelper.format(date, 'YYYY-MM-DD'); } export function convertTask2Event(rawTasks: ITask[]): any[] { let eventArray: any[] = []; for (const rawTask of rawTasks) { const eventItem = { id: rawTask.id, name: rawTask.name, projectId: rawTask.projectId, projectName: rawTask.projectName, progress: rawTask.progress, hour: rawTask.hour, message: rawTask.message, actualStart: formatDate2(rawTask.actualStart), startDate: formatDate2(rawTask.startDate), endDate: formatDate2(rawTask.endDate), planworktime: rawTask.planworktime, resourceId: rawTask.resourceId, eventColor: rawTask.eventColor }; eventArray.push(eventItem); } return eventArray; } export function convertResourceList(resources: IResource[]) { let newResources: ResourceModel[] = []; for (const resource of resources) { if (resource.resourceName !== undefined && resource.resourceRole !== undefined) { const newResource = new ResourceModel({ id: resource.id, name: resource.resourceName, }); newResources.push(newResource); } } return newResources; } export function CustomCalendar(props: CustomCalendarContainerProps): ReactElement { const calendarRef = useRef<BryntumCalendar>(null); const project = useRef<BryntumCalendarProjectModel>(null); const [events] = useState(projectData.events); const [timeRanges] = useState<TimeRangeModelConfig>(projectData.timeRanges.rows as unknown as TimeRangeModelConfig); console.info(props.sampleText); const resourceList = useMemo(() => { if (props.resourceList.status === ValueStatus.Available && props.resourceList.items) { const iResourceList: IResource[] = []; for (const objItem of props.resourceList.items) { const newId = mapMxID(props.resourceId.get(objItem).value); if (newId) { const newResource: IResource = { obj: objItem, //id: newId, //id: props.resourceName.get(objItem).value || '1', id: props.resourceId.get(objItem).value?.toString() ?? '1', resourceName: props.resourceName.get(objItem).value, resourceRole: props.resourceRole.get(objItem).value }; iResourceList.push(newResource); } } //setTeamUserSet(iResourceList); return convertResourceList(iResourceList); } }, [props.resourceList, props.resourceName, props.resourceRole, props.resourceId ]); const events2 = useMemo(() => { if (props.objectList.status === ValueStatus.Available && props.objectList.items) { const flatTaskList: ITask[] = []; // Iterator through the Mendix data and make a flat array of tasks (all children attributes are empty) for (const objItem of props.objectList.items) { const newId = mapMxID(props.id.get(objItem).value); // Example of how to parse the data from Mendix // only create a task if it's ID is valid if (newId) { const newTask: ITask = { obj: objItem, id: newId, projectId: props.projectId.get(objItem).value ?? 'NULL', projectName: props.projectName.get(objItem).value ?? 'NULL', progress: props.progress.get(objItem).value?.toNumber() ?? undefined, hour: props.hour.get(objItem).value?.toNumber() ?? undefined, message: props.message.get(objItem).value ?? '', actualStart: props.actualStart.get(objItem).value, startDate: props.planStartDate.get(objItem).value, planworktime: props.planworktime.get(objItem).value?.toNumber() ?? 0, endDate: props.planEndDate.get(objItem).value, name: props.taskName.get(objItem).value ?? 'NULL', //resourceId: props.taskOwner.get(objItem).value || '1',//'bryntum', resourceId: (props.projectId.get(objItem).value ?? 'NULL') + '-' + props.taskOwner.get(objItem).value || '1',//'bryntum', eventColor: 'green' }; flatTaskList.push(newTask); } } console.info(`useMemo processed flatTaskList count=${flatTaskList.length} `, flatTaskList); if (flatTaskList) { return convertTask2Event(flatTaskList); } else { console.info("useMemo no task found with parentId undefined"); return undefined; } } }, [props.objectList, props.id, props.taskName, props.planStartDate, props.planEndDate]); let bryntumEvents = events2 != undefined ? events2 : []; console.info("bryntumEvents", bryntumEvents); console.info("events", events); let resourcesCollection = resourceList != undefined ? resourceList : []; return ( <div id="container"> <Fragment> <BryntumCalendarProjectModel ref={project} events={bryntumEvents} resources={resourcesCollection} timeRanges={Array.isArray(timeRanges) ? timeRanges : undefined} /> <BryntumCalendar ref={calendarRef} project={project} {...calendarProps} /> </Fragment> </div> ); }

Post by tasnim »

You could listen to https://bryntum.com/products/calendar/docs/api/Scheduler/feature/EventEdit#event-beforeEventSave to do some action before saving the event, or if you want to do some action after save, you could listen to https://bryntum.com/products/calendar/docs/api/Scheduler/feature/EventEdit#event-afterEventSave

Best regards,
Tasnim

How to ask for help? Please read our Support Policy


Post by Animal »

There are other ways that an event can change apart from just via the event edit dialog.

Drag move, drag create, drag resize.

Copy/paste

Right click -> Create event

I assume you want to save all changes to the DB.

I remember a similar question about saving data in response to only dragging. I answered that, but the poster seems to have deleted all his posts and only my answers remain: viewtopic.php?t=32242


Post by bin_yu »

Hi, I tried to use onAfterEventSave to do a saving logic(see the following screenshot), but it seemed that only one record can be saved to the DB at clicking save button of editor. How to do batch saving? Because I want to use a button to save all the modifications on the page to the database. Any solution?

2025-05-09 How to do batch saving.png
2025-05-09 How to do batch saving.png (139.11 KiB) Viewed 96 times

Post by marcio »

Hey bin_yu,

To perform batch saving of all modifications on the page, you can utilize the crudManager to handle data syncing. The crudManager can be configured with a syncUrl and autoSync set to false, allowing you to manually trigger the sync operation when needed, such as when a button is clicked.

Here's a basic example of how you might set this up:

const calendar = new Calendar({
    // Other configurations...
    crudManager : {
        loadUrl  : 'data/data.json',
        syncUrl  : 'your-sync-url-here',
        autoLoad : true,
        autoSync : false
    }
});

// Function to trigger batch save
function saveAllChanges() {
    calendar.crudManager.sync();
}

// Attach the function to a button click event
document.getElementById('saveButton').addEventListener('click', saveAllChanges);

This approach ensures that all changes made to the calendar are sent to the server in one batch when the button is clicked.

For more detailed information, you can refer to the CrudManager Guide.

Best regards,
Márcio

How to ask for help? Please read our Support Policy


Post Reply