Our pure JavaScript Scheduler component


Post by manirajan s »

Hi,

I have handled the useEffect for adding event data from the dragged event that is dropped onto the scheduler. However, scheduler.crudManager.changes only shows the event payload as "added", and not the assignment. How can I include the assignment data in the "added" payload?

  //Drag and Drop functionalities
  useEffect(() => {
    // Get the scheduler element once it's rendered
    const scheduler = schedulerProRef.current?.instance;
    if (!scheduler) return;

const schedulerElement = scheduler.element;
if (!schedulerElement) return;

// Create a tip element that will be shown during drag
const tipElement = document.createElement('div');
tipElement.className = 'scheduler-drag-tip';
tipElement.style.position = 'absolute';
tipElement.style.display = 'none';
tipElement.style.color = 'white';
tipElement.style.padding = '0.6rem 1rem';
tipElement.style.background = 'rgba(73, 73, 73)';
tipElement.style.borderRadius = '3px';
tipElement.style.boxShadow = '2px 2px 4px rgba(0,0,0,0.2)';
tipElement.style.zIndex = '9999';
tipElement.style.pointerEvents = 'none';
document.body.appendChild(tipElement);

// Add event listeners for drag events
const handleDragOver = (event: DragEvent) => {
  event.preventDefault(); // Needed to allow drop
  schedulerElement.classList.add('drag-over');
  // Get the time position under the cursor
  const coordinate = scheduler.getDateFromCoordinate(
    event.clientX,
    'round',
    false,
  );

  // Get the resource at this position
  const resource = scheduler.resolveResourceRecord(event);
  if (coordinate && resource) {
    // Format time in a friendly way
    const formattedTime = DateHelper.format(coordinate, 'HH:mm');
    const formattedDate = DateHelper.format(coordinate, 'ddd, MMM D');
    // Show the tooltip with time and resource information
    tipElement.innerHTML = `
      <div style="font-weight: bold">${formattedTime}</div>
    `;
    // Position the tip element near the cursor
    tipElement.style.left = `${event.clientX + 10}px`;
    tipElement.style.top = `${event.clientY + 10}px`;
    tipElement.style.display = 'block';
  }
};

const handleDragEnter = (event: DragEvent) => {
  event.preventDefault();
  schedulerElement.classList.add('drag-over');
};

const handleDragLeave = (event: DragEvent) => {
  schedulerElement.classList.remove('drag-over');
  tipElement.style.display = 'none'; // Hide the tip when leaving
};

const handleDrop = (event: DragEvent) => {
  event.preventDefault();
  schedulerElement.classList.remove('drag-over');
  tipElement.style.display = 'none';

  // Get the drop position and resource
  const coordinate = scheduler.getDateFromCoordinate(
    event.clientX,
    'round',
    false,
  );

  const resource = scheduler.resolveResourceRecord(event);
  if (coordinate && resource) {
    try {
      // Try to get JSON data first - this is what our grid cells set
      const jsonData = event.dataTransfer.getData('application/json');

      if (jsonData) {
        let taskData;
        try {
          taskData = JSON.parse(jsonData);
        } catch (error) {
          taskData = {
            name: 'Error parsing data',
            duration: '2h',
            color: 'red',
          };
        }

        // Parse the duration
        let durationMs = 2 * 60 * 60 * 1000; // Default: 2 hours in milliseconds
        if (taskData.duration) {
          const durationStr = String(taskData.duration);
          // Parse different duration formats
          if (durationStr.includes('m')) {
            // Minutes format: "120m"
            const minutes = parseInt(durationStr.replace(/m/i, ''), 10);
            if (!isNaN(minutes)) {
              durationMs = minutes * 60 * 1000;
            }
          } else if (durationStr.includes('h')) {
            // Hours format: "2h"
            const hours = parseInt(durationStr.replace(/h/i, ''), 10);
            if (!isNaN(hours)) {
              durationMs = hours * 60 * 60 * 1000;
            }
          } else if (durationStr.includes(':')) {
            // HH:MM format: "2:00"
            const [hours, minutes] = durationStr
              .split(':')
              .map((part) => parseInt(part, 10));
            if (!isNaN(hours) && !isNaN(minutes)) {
              durationMs = hours * 60 * 60 * 1000 + minutes * 60 * 1000;
            }
          } else {
            // Assume numeric hours
            const hours = parseInt(durationStr, 10);
            if (!isNaN(hours)) {
              durationMs = hours * 60 * 60 * 1000;
            }
          }
        }
        
        // Generate a unique ID for the new event
        const newEventId = `${new Date().getTime()}`;

        // Create a new event with proper formatting for the CrudManager
        const newEvent = {
          // $PhantomId: Number(newEventId),
          id: newEventId,
          allDay: taskData.allDay || false,
          name: taskData.name || 'New Task',
          startDate: coordinate,
          endDate: `${new Date(coordinate.getTime() + durationMs)}`,
          eventColor: taskData.color,
          resourceId: resource.id,
        };

        // setEvents((prevEvents) => [...prevEvents, newEvent]);
        console.log('New Event:', newEvent);
      
        // Create a corresponding assignment
        const newAssignment = {
          id: `assignment-${new Date().getTime()}`,
          // eventId: Number(newEvent.$PhantomId),
          eventId: newEventId,
          resourceId: resource.id,
        };

        // setAssignments((prevAssignments) => [...prevAssignments, newAssignment]);
        
        console.log('New Assignment:', newAssignment);

        console.log('Addition changes', scheduler.crudManager.changes);
        // Add the new records to the scheduler's stores
        scheduler?.eventStore.add(newEvent);
        console.log('Addition changes', scheduler.crudManager.changes);
        scheduler?.assignmentStore.add(newAssignment);
      } else {
        console.warn('No JSON data found in the drop event');
      }
    } catch (error) {
      console.error('Error handling drop:', error);
    }
  } else {
    console.warn('Invalid drop location - missing coordinate or resource');
  }
};
const handleDragEnd = () => {
  tipElement.style.display = 'none';
  schedulerElement.classList.remove('drag-over');
};

// Add the event listeners
schedulerElement.addEventListener('dragover', handleDragOver);
schedulerElement.addEventListener('dragenter', handleDragEnter);
schedulerElement.addEventListener('dragleave', handleDragLeave);
schedulerElement.addEventListener('drop', handleDrop);
document.addEventListener('dragend', handleDragEnd);

// Return cleanup function
return () => {
  if (schedulerElement) {
    schedulerElement.removeEventListener('dragover', handleDragOver);
    schedulerElement.removeEventListener('dragenter', handleDragEnter);
    schedulerElement.removeEventListener('dragleave', handleDragLeave);
    schedulerElement.removeEventListener('drop', handleDrop);
    document.removeEventListener('dragend', handleDragEnd);
  }
  // Remove the tip element
  if (document.body.contains(tipElement)) {
    document.body.removeChild(tipElement);
  }
};
  }, [schedulerProRef.current?.instance]);
  

PFA Image for your reference.

addition_ass_issue_payload.png
addition_ass_issue_payload.png (85.99 KiB) Viewed 168 times

Post by tasnim »

Hey,

It's hard to say without reproducing locally. Could you please share a runnable test case so we can check locally what's wrong?

Best regards,
Tasnim

How to ask for help? Please read our Support Policy


Post by manirajan s »

Hi Tasnim,

It’s not possible to share runnable code due to runtime dependencies. So, I had shared the code blog.
Please help me on adding events while drag and drop. During the sync call, these same events should also be added to the CRUD manager.


Post by alex.l »

Hi,

How do you specify assignments? If you use resourceId notation, that's expected to not see assignments in payload. To have it, you need to avoid using resourceId to assign and add a record into assignmentStore.

eventStore.add({id : 2, name : 'Dropped event'});
assignmetStore.add({id : 11, eventId : 2, resourceId : 2});

All the best,
Alex Lazarev

How to ask for help? Please read our Support Policy

We do not write the code in bounds of forum support. If you need help with development, contact us via bryntum.com/services


Post by manirajan s »

Thanks alex. Now, getting changes while drag and drop as added but still in the sync payload its not syncing as already told


Post by ghulam.ghous »

Ok, please share more details about what is the current behaviour and what is the expected behaviour. I have looked up your code snippet, and in that you were using the resourceId to for the assignments, which means it is single assignment mode and the assignments are not going to be synced with the backend as Alex mentioned. Because when you are gonna reload the data, the assignments are going to be generated from the resourceId. Maybe show us the event data you are adding.

Also please check what is the value of scheduler.eventStore.usesSingleAssignment in the console.


Post by manirajan s »

Hi Ghulam,

PFA video for your reference.

Explanation of Video Navigation and Functionality
Initially, I drag an event from the grid and drop it into a scheduler. The taskData represents the incoming data being dragged. I add this data to our events, and likewise, the corresponding assignment data is added to our assignments. The event and assignment structures are extracted from the dragged item.

After dropping the event, I click an external "Save" button, which triggers a sync call. During this process, I log the response in the console. I noticed that the sync emits all events and resources — however, the newly added event and its assignment are missing from the response. The dropped event disappears after sync, and its assignment data is also not retained.

Expected Behavior
The newly added event and its corresponding assignment should remain visible in the scheduler and be included in the response after the sync.

How can I ensure the newly added event and assignment are correctly retained and shown in the scheduler after sync? If there's any mistake or gap in the code, could someone kindly point it out or suggest a correction?

workflow.mp4
(28.48 MiB) Downloaded 5 times

Post by ghulam.ghous »

This is weird. Must be missing something somewhere, can you please show me what is the payload for the sync request by inspecting the network tab and sync call? Does it include the assignments?


Post by manirajan s »

Hi Ghulam,

Attaching payload image for your reference.

payload.png
payload.png (145.05 KiB) Viewed 81 times

It doesn't include assignments


Post by ghulam.ghous »

Thanks for sharing that. Also please check the value of scheduler.eventStore.usesSingleAssignment and expand the dropped event from the added array in the payload. Please understand that we don't have much context about what is happening there, as it is difficult for you to share a small test case. Another thing, please drop the drag and drop related code here, I'll try to use that in our online examples and let's see if I can replicate the issue there. And which version of Scheduler you are using, it is possible that there might be some bug, that later on got fixed.


Post Reply