I'm working with Bryntum Scheduler Pro and currently implementing recurring event support. I have a question regarding the best way to handle custom data control when a recurring event is split after the user chooses "Edit this occurrence" or "Edit all future occurrences".
When a split occurs:
A new EventModel and associated AssignmentModel are created automatically and the old one updated from what I'm getting is the workflow. Correct me if I'm wrong.
I need to capture and control the data of these newly created records for the event and the assignment and send them through one only endpoint so I can save it in the database with the correct ID's.
First I did it with 2 different listeners (one for the EventStore.on.beforeAdd and another AssignmentStore.on.beforeAdd) and 2 different endpoints but I'm having problems cause my endpoits are async so they will run at the same time causing it to break.
I need some help on how to do this cause I'm currently in the dark on the best way to handle this.
Perhaps you could use the https://bryntum.com/products/schedulerpro/docs/api/SchedulerPro/feature/TaskEdit#event-beforeEventSave event handler to capture changes before they are saved. This event allows you to modify the event data before it is committed to the store. You can then consolidate the data from both the EventModel and AssignmentModel and send it to a single endpoint. You can use the folllowing approach:
Use the beforeEventSave event to capture the event data before it is saved.
Modify the event data as needed.
Use a single endpoint to send the consolidated data for both the event and assignment.
Here's a code snippet to illustrate:
scheduler.on('beforeEventSave', async ({ eventRecord }) => {
// Modify eventRecord as needed
const eventData = eventRecord.data;
// Fetch related assignment data
const assignmentData = scheduler.assignmentStore.getAssignmentsForEvent(eventRecord);
// Consolidate data
const dataToSend = {
event: eventData,
assignments: assignmentData
};
// Send to your endpoint
await sendToEndpoint(dataToSend);
});
This way, you ensure that both the event and its assignments are processed together, avoiding issues with asynchronous operations.
If that doesn't solve your issue, please let us know.
eventStore.on({
beforeEventSave: ({record}: any) => {
console.log('event save')
if (!this.isAddingEvent) {
const assignmentRecord = this.assignmentStore.getAssignmentsForEvent(record);
const lastScheduleRecord = this.project.eventStore.last;
let newEventId = 1;
if (lastScheduleRecord) {
newEventId = Math.max(...this.project.assignmentStore.getRange().map((assignment: any) => assignment.id)) + 1;
}
record.set({
id: newEventId
});
this.addEventAndSendToSignalR(record, assignmentRecord);
} else {
this.isAddingEvent = false;
}
},
update: ({ record, changes }: any) => {
console.log('update')
if (!this.isExternalUpdate) {
const assignmentRecord = this.assignmentStore.getAssignmentsForEvent(record);
if ('duration' in changes || 'startDate' in changes || 'durationUnit' in changes || 'note' in changes || 'recurrenceRule' in changes) {
if (assignmentRecord[0]) {
this.sendUpdateToSignalR(record, assignmentRecord[0]);
}
}
} else {
this.isExternalUpdate = false;
}
},
beforeRemove: ({ records }: any) => {
this.isStandBy = true;
records.forEach((record: any) => {
this.deleteEventAndAssignmentsAndSendToSignalR(record);
});
},
});
//Listeners on the AssignmentStore
assignmentStore.on({
beforeAdd: ({records}: any) => {
console.log('assignment')
if (!this.isAddingAssignment) {
if (records) {
records.forEach((record: any) => {
const lastScheduleRecord = this.project.assignmentStore.last;
let newAssignmentId = 1;
if (lastScheduleRecord) {
newAssignmentId = Math.max(...this.project.assignmentStore.getRange().map((assignment: any) => assignment.id)) + 1;
}
record.set({
id: newAssignmentId
});
this.addAssignmentAndSendToSignalR(record);
});
}
} else {
this.isAddingAssignment = false;
}
},
update: ({ record, changes }: any) => {
this.isExternalUpdate = true;
if ('resourceId' in changes ) {
const eventRecord : any = this.eventStore.getById(record.eventId);
if (eventRecord) {
this.sendUpdateToSignalR(eventRecord, record);
}
}
},
beforeRemove: ({records}:any) =>{
if (!this.isStandBy) {
var event = this.eventStore.getById(records[0].eventId)
if (this.eventStore.getAssignmentsForEvent(event as SchedulerEventModel).length > 1) {
records.forEach((record: any) => {
if (record) {
this.deleteAssignmentAndSendToSignalR(record);
}
});
return true;
} else {
const errorUnassignment = this._translocoService.translate('VEC:BryntumUnassignment')
if (!this.messageSent) {
this.messageSent = true;
if (scheduler.features.taskEdit.isEditing) {
//@ts-ignore
this.scheduler.features.taskEdit.editor.close();
}
Toast.show({
html: errorUnassignment,
timeout: 10000,
style: 'color: red'
});
return false;
} else {
this.messageSent = false;
return false;
}
}
} else {
this.isStandBy = false;
return true;
}
},
});
So I can handle all the creates, updates and deletes from assignments and events.
Doing that will make it so the assignment add is fired before and one thing I noticed is that when we do that it will fire the beforeAdd from the assignment then the update from the event 2 times.
If I do this with a beforeAdd but using the same example you gave will it work to?