Our pure JavaScript Scheduler component


Post by Jerome Cauchon »

Hi,
i'm trying to figure how to use state in scheduler features. Changes to the state doesn't seems to update scheduler features. What is the right way to do it? See attached project.

Thanks

const [selectedEvent, setSelectedEvent] = useState<EventModel | null>(null);
...
const eventTooltipFeature = {
        allowOver: true,
        bbar: [
            {
                text: 'beer',
                icon: 'b-fa b-fa-fw b-fa-beer',
                onClick() {
                    alert(selectedEvent?.name); // selectedEvent always null
                  },
            },
        ],
        template: ({ eventRecord }: { eventRecord: EventModel }) =>
            ReactDOMServer.renderToString(<EventTooltipTemplate eventRecord={eventRecord} />),
    };
    const onEventSelectionChange = useCallback(({ selected }: { selected: EventModel[] }) => {
        setSelectedEvent(selected.length ? selected[0] : null);
    }, []);
    ...
    <BryntumSchedulerPro
                ref={schedulerRef}
                {...schedulerConfig}
                eventTooltipFeature={eventTooltipFeature}
                onEventSelectionChange={onEventSelectionChange}
            />
Attachments
basic_copy 3.zip
(3.48 MiB) Downloaded 34 times

Post by saki »

If we look in the documentation at https://bryntum.com/docs/scheduler/#Scheduler/view/Scheduler#config-features we see a blue circle with c inside what stands for config which is an option passed to the scheduler at the configuration time and is not supposed to be changed at runtime. This holds true for all features. A feature takes a configuration object and instantiates its class, for example https://bryntum.com/docs/scheduler/#Scheduler/feature/EventTooltip. Any subsequent assignments would overwrite this class and it would stop working.

To access a feature at runtime, for example to enable/disable it, we need to drill down to the instance of its class and access that. For example:

useEffect(()=>{
    schedulerRef.current.instance.features.eventTooltip.disabled = disabledState;
}, [disabledState])

Post by Jerome Cauchon »

Hi Saki, it's exactly what i did for my event menu. Based on dependenciesRecord state property, i changed my custom menu item text for "show" or "hide" and update the onItem handler(see code below).

I tried to do the same thing with the event tool tip, but i did not find the way to achieve the same kind of thing. I need something like the processItems of the eventMenu to show/hide my bbar option. Is it possible to do that with the beforeShow event? If so, how?

Thanks Saki for your help!

const [selectedEvent, setSelectedEvent] = useState<EventModel | null>(null);

const eventTooltipFeature = {
    allowOver: true,
    bbar: [
        {
            text: 'set selected',
            icon: 'b-fa b-fa-fw b-fa-eye',
            onClick() {
                // @ts-ignore
                setSelectedEvent(this.up('tooltip').eventRecord);
              },
        },
        {
            text: 'unset selected',
            icon: 'b-fa b-fa-fw b-fa-eye-slash',
            onClick() {
                setSelectedEvent(null);
              },
        },
    ],
    template: ({ eventRecord }: { eventRecord: EventModel }) =>
        ReactDOMServer.renderToString(<EventTooltipTemplate eventRecord={eventRecord} />),
};

useEffect(() => {
    // Hide one of the two bbar option. If selectedEvent == toolip record, hide the 'set selected' bbar option
    // otherwise, hide the 'unset selected'.

}, [selectedEvent]);

Working code with event menu:

  useEffect(() => {
    if (schedulerRef.current) {
      schedulerRef.current.instance.features.eventMenu.items.dependenciesEvent.onItem = ({ eventRecord }: { eventRecord: PlanifEvent }) => {
        setDependenciesRecord(eventRecord.id === dependenciesRecord?.id ? undefined : eventRecord);
      };

  schedulerRef.current.instance.features.eventMenu.processItems = ({
    eventRecord,
    items,
  }: {
    eventRecord: PlanifEvent;
    items: { dependenciesEvent: MenuItemConfig };
  }) => {
    items.dependenciesEvent.disabled = !eventRecord.linkedEventIds.length;
    items.dependenciesEvent.text = eventRecord.id === dependenciesRecord?.id ? t('planning:hideLinkedTask') : t('planning:showLinkedTask');
    items.dependenciesEvent.icon = eventRecord.id === dependenciesRecord?.id ? 'b-fa b-fa-fw b-fa-eye-slash' : 'b-fa b-fa-fw b-fa-eye';
  };
}
  }, [dependenciesRecord, setDependenciesRecord, t]);

Post by Jerome Cauchon »

Hi Saki, i make it work using the beforeShow event and by setting a selectedEvent on the eventTooltip instance. It's pretty complicated for a simple behavior! Maybe you have suggestion for a cleanest way to get it work?

By the way, your Tooltip typing does not contains eventRecord prop, only record which is always null.

Thanks

const eventTooltipFeature = {
        allowOver: true,
        bbar: [
            {
                text: 'set selected',
                icon: 'b-fa b-fa-fw b-fa-eye',
                onClick() {
                    // @ts-ignore
                    const tooltip = this.up('tooltip');
                    setSelectedEvent(tooltip.eventRecord);
                    tooltip.hide();  
}, }, { text: 'unset selected', icon: 'b-fa b-fa-fw b-fa-eye-slash', onClick() { // @ts-ignore const tooltip = this.up('tooltip'); setSelectedEvent(null); tooltip.hide(); }, }, ], listeners:{ beforeShow: ({source}:{source: any}) => { // **** your Tooltip typing does not contains eventRecord prop, only record which is always null const isSelected = source.eventRecord.id === schedulerRef.current.instance.features.eventTooltip.selectedEvent?.id; // @ts-ignore const bbar: any[] = source.bbar.items; bbar[0].hidden = isSelected; bbar[1].hidden = !isSelected; } }, template: ({ eventRecord }: { eventRecord: EventModel }) => ReactDOMServer.renderToString(<EventTooltipTemplate eventRecord={eventRecord} />), }; useEffect(() => { if (!schedulerRef.current.instance.features.eventTooltip) return; schedulerRef.current.instance.features.eventTooltip.selectedEvent = selectedEvent; }, [selectedEvent]);

Post by saki »

I'm glad you made it working, however, I thought you could use tooltip.eventRecord for the purpose and you would not need to set it as a state variable.

You are right, the typing is missing. We continually improve typings and I've made a note about this omission. Thank you for reporting.


Post by Jerome Cauchon »

Thanks Saki! Sorry i was out last week!


Post Reply