tui.calendar icon indicating copy to clipboard operation
tui.calendar copied to clipboard

When resizing event `beforeUpdateEvent` called multiple times in month view

Open FFloou opened this issue 2 years ago • 10 comments

Version

v.2.1.2

Test Environment

Chrome

Current Behavior

// 'onBeforeUpdateEvent' logged 5 times in console when I resize event
const onBeforeUpdateEvent: ExternalEventTypes['beforeUpdateEvent'] = res=>{
    consle.log('onBeforeUpdateEvent');
}

<Calendar onBeforeUpdateEvent={onBeforeUpdateEvent}/>

Expected Behavior

I'm trying to use my own update event function with onBeforeUpdateEvent. Dragging to another day works well... But when resize event,onBeforeUpdateEvent called 5 times so my custom update event happens multiple times too. I'm wondering is there any solution to solve this problem.

FFloou avatar Sep 14 '22 02:09 FFloou

@FFloou

I couldn't reproduce the problem you mentioned. Can you provide any example code reproducing the same problem?

FYI it might be related to the equality check between props while re-render.

https://github.com/nhn/tui.calendar/blob/main/apps/react-calendar/docs/en/guide/getting-started.md#%EF%B8%8F-note-for-passing-props

adhrinae avatar Sep 14 '22 05:09 adhrinae

Closing since there's been no feedback and it cannot be reproduced.

adhrinae avatar Sep 27 '22 23:09 adhrinae

Sorry to necro-bump this issue but I'm seeing the same behavior unfortunately. I'm using the react component via a webcomponent wrapper called by an Elm app and the React component is only being rendered once as the calendar instance is in a ref.

But when I drag-n-drop the drag handle of an existing event the onBeforeUpdateEvent callback is being fired multiple times.

Here's the component

const TuiCalendar = ({
  timescale: view,
  events, cursor, toElm: toElm_, dialogClosed
}) => {

  const tuiRef = useRef(null)
  const tui = useCallback(() => tuiRef.current?.getInstance?.(), [])

  useEffect(() => tui().setDate(cursor), [tui, cursor])

  useEffect(() => {
    if (dialogClosed) {
      tui().clearGridSelections()
    }
  }, [tui, dialogClosed])

  const toElm = useCallback((type, body) => {
    toElm_(`tui_${ type }`, body)
  }, [toElm_])

  const onClickEvent = useCallback(({ event }) => {
    toElm('event_clicked', event)
  }, [toElm])

  const onSelectDateTime = useCallback((evt) => {
    const start = evt.start.getTime()
    const end = evt.end.getTime()
    toElm('range_selected', { ...evt, start, end })
  }, [toElm])

  const onBeforeUpdateEvent = useCallback((updates) => {
    const { event, changes } = updates
    tui().updateEvent(event.id, event.calendarId, changes)

    const start = (changes.start ?? event.start)?.getTime()
    const end = (changes.end ?? event.end)?.getTime()

    toElm('range_updated', { ...event, start, end })
  }, [tui, toElm])

  return (
    <Tui
      // Config
      ref={ tuiRef }
      height="100%"
      view={ view }
      events={ events }

      // Callbacks / Handlers
      onSelectDateTime={ onSelectDateTime }
      onClickEvent={ onClickEvent }

      // Mutations
      onBeforeUpdateEvent={ onBeforeUpdateEvent }
    />
  )
}
TuiCalendar.propTypes = Tui.propTypes

erlandsona avatar Dec 21 '22 17:12 erlandsona

@erlandsona I wonder if the TuiCalendar component's props bypass the wrapper's equality check.

Can you give us any sample sandbox(codesandbox, stackbtliz, etc.) to reproduce this problem?

adhrinae avatar Dec 26 '22 23:12 adhrinae

image

kipa-zhang avatar Jan 06 '23 09:01 kipa-zhang

Same problem image

kipa-zhang avatar Jan 06 '23 09:01 kipa-zhang

I confirmed that It occurs when you resize any all-day event in the month view.

There might be a problem in this function but I cannot look deeper at this moment.

adhrinae avatar Jan 09 '23 00:01 adhrinae

I'm new to using ToastUI Calendar but I've just come across this same issue.

As discussed it only happens when resizing events and it can be for an all day or timed event.

The problem looks to be that the function ResizingGuideByRow() is called once per row and this calls useDayGridMonthEventResize() which runs the beforeUpdateEvent.

You can see this if you setup the calendar with isAlways6Weeks: false and then on a month that shows 4 or 5 rows the number of calls to beforeUpdateEvent is the same.

I've only looked at the code briefly and I can't see exactly how it's supposed to be working but to me it seems that either:-

  1. All of the rows should be processed and then the beforeUpdateEvent should be called once.
  2. The 'shouldUpdate' check that surrounds the beforeUpdateEvent should be changed to take into account the rowIndex so the beforeUpdateEvent is only called when it matches the event being resized.

In useDayGridMonthEventResize() if you change the line

const shouldUpdate = !isDraggingCanceled && (currentGridPos.rowIndex === eventStartDateRowIndex && currentGridPos.columnIndex >= eventStartDateColumnIndex || currentGridPos.rowIndex > eventStartDateRowIndex);

to

const shouldUpdate = !isDraggingCanceled && (rowIndex === eventStartDateRowIndex && (currentGridPos.columnIndex >= eventStartDateColumnIndex || currentGridPos.rowIndex > eventStartDateRowIndex));

then this seems to fix the problem however it seems to me that a rowIndex check should be taking place much earlier.

Ollie222 avatar May 11 '23 09:05 Ollie222

I found that this issue is still opened... This issue seems a problem of calendar itself and it takes some time to be fixed.

What I wanted was fetching API only once which included in update function, so I ended up wrapping with debounce.

const onBeforeUpdateEvent: ExternalEventTypes['beforeUpdateEvent'] = _.debounce(res=>{
    consle.log('onBeforeUpdateEvent');
}, 50)

FFloou avatar Feb 15 '24 05:02 FFloou