Our pure JavaScript Scheduler component


Post by roman_e »

Hi

Is it possible to append the scheduler at a later time after creation?
I tried to set the config "appendTo" at a later time and also tried the WidgetHelper, but I don't get it to work.

Post by sergey.maltsev »

Hi!

Currently we have no public way to do this.
But you can try this code in https://www.bryntum.com/examples/scheduler/basic/.
document.getElementById('container').appendChild(scheduler.element);
scheduler.render();
Please note that render() is private and it can be removed lately or replaced with new code.

I've created this ussue to make public method for this
https://github.com/bryntum/support/issues/38

Post by dennisli »

Is there a way to do this after a scheduler has already been rendered? ie i'm using bryntum with react and the container component may be destroyed, but I'd like to hold onto the bryntum scheduler instance.

I get the following error on scheduler.render() when i re-render the react container

Uncaught Error: Id b-scheduler-4-dependency-tip already in use
    at Function.register (scheduler.umd.js:28996)
    at Tooltip.set (scheduler.umd.js:66291)
    at Tooltip.get (scheduler.umd.js:1016)
    at Tooltip.set (scheduler.umd.js:66142)
    at set (<anonymous>)
    at _set (scheduler.umd.js:161192)
    at Tooltip.set (scheduler.umd.js:58272)
    at Tooltip.get (scheduler.umd.js:1016)
    at Tooltip.startConfigure (scheduler.umd.js:64587)
    at Tooltip.startConfigure (scheduler.umd.js:49256)
    at Tooltip.startConfigure (scheduler.umd.js:59172)
    at Tooltip.setConfig (scheduler.umd.js:634)
    at Tooltip.setConfig (scheduler.umd.js:49246)
    at Tooltip.configure (scheduler.umd.js:583)
    at Tooltip.construct (scheduler.umd.js:313)
    at Tooltip.construct (scheduler.umd.js:38775)
    at Tooltip.construct (scheduler.umd.js:40104)
    at Tooltip.construct (scheduler.umd.js:64575)
    at new Base (scheduler.umd.js:293)
    at Tooltip._createSuperInternal (scheduler.umd.js:38719)
    at new Localizable (scheduler.umd.js:38760)
    at Tooltip._createSuperInternal (scheduler.umd.js:39872)
    at new Events (scheduler.umd.js:40076)
    at Tooltip._createSuperInternal (scheduler.umd.js:39226)
    at new Delayable (scheduler.umd.js:39274)
    at Tooltip._createSuperInternal (scheduler.umd.js:64489)
    at new Widget (scheduler.umd.js:64553)
    at Tooltip._createSuperInternal (scheduler.umd.js:49158)
    at new Container (scheduler.umd.js:49234)
    at Tooltip._createSuperInternal (scheduler.umd.js:58060)
    at new Panel (scheduler.umd.js:58125)
    at Tooltip._createSuperInternal (scheduler.umd.js:59120)
    at new Popup (scheduler.umd.js:59161)
    at Tooltip._createSuperInternal (scheduler.umd.js:63152)
    at new Tooltip (scheduler.umd.js:63247)
    at Dependencies.createTooltip (scheduler.umd.js:119136)
    at Dependencies.render (scheduler.umd.js:119062)
    at ScheduleTooltip.functionChainRunner (scheduler.umd.js:41150)
    at Scheduler.plugInto.<computed> [as render] (scheduler.umd.js:41127)

Post by mats »

Do you have a test case for us that we can check?


Post by dennisli »

Is there an easy boilerplate setup for providing test cases? This is my react component.

const BryntumContainer = () => {
  const id = useSelector(apiSelectors.shared.getId);
  const schedulerEl = useRef<Scheduler | null>(null);
  const el = useRef<HTMLDivElement>(null);
  const dispatch = useDispatch();

  const myScheduler = useSelector(appSelectors.getBryntumScheduler);

  useEffect(() => {
    if (!id) {
      return
    }

if (!myScheduler) {
  const config = getInitSchedulerConfig(id, el.current ?? '', s.bryntumScheduler);
  schedulerEl.current = new Scheduler(config);

  postSchedulerSetup(schedulerEl.current);
  dispatch(appActions.setBryntumSchedule({ bryntumScheduler: schedulerEl.current }));
} else {
  schedulerEl.current = myScheduler;
  el.current?.appendChild(myScheduler.element);
  (myScheduler as any).render();
}

  }, [id, dispatch]);

  return <div className={s.BryntumContainer} ref={el} />;
};

Post by fabio.mazza »

Hi dennisli,

You can use Scheduler React Simple Demo to create your test case.

Best regards,
Fabio


Post by dennisli »

I'm not sure what you mean -- that's a demo page. I don't see a sandbox/boilerplate to insert my code? And its react lifecycle is different from mine (I recall writing my own react component instead of using the example because it did not handle teardown logic). ie the snippet above would be a replacement for BryntumScheduler.js

the difference being that it does not have an equivalent of componentWillUnmount because it specifically wants the engine to persist without a react component ie


// React component removed, destroy engine
componentWillUnmount() {
    this.schedulerInstance.destroy();
}

Post by saki »

Well, it might be easier than it looks so I'll describe the possible approach. Mind please that I haven't tested it, nevertheless, I'm quite positive that it should work.

The problem is that React can in some circumstances destroy the HTML markup of the scheduler, therefore, we want to preserve it. If we can identify and hook just before the markup is destroyed then we can do something like:

scheduler.hide();  // scheduler is the native instance, not the React component
document.body.appendChild(scheduler.element);

// let React to do its destruction

Now the scheduler element is appended to the body and invisible but existing.

When we need the scheduler visible again in a container element then:

container.appendChild(scheduler.element);
scheduler.show();

Post by dennisli »

Thanks! that seemes to have worked - but what's the purpose of document.body.appendChild(scheduler.element);? Is that just to keep a pointer/reference? (I have the scheduler engine stored in redux so that's a non issue for me)

Anyway, the one caveat though is that on scheduler.show() it loses it's previous zoom position. That's fine, and I can cache/save that, but is that because that value is lost on .hide()?


Post by saki »

The purpose it to get it out of the part of the DOM tree that is going to be destroyed by the routing. It is not about preserving JavaScript instance of the Scheduler but about preserving its HTML markup.

The other option to hide/show would be to set display on scheduler element:

scheduler.element.style.display = ''; // to show
scheduler.element.style.display = 'none'; // to hide

Despite of all said so far, the best would be to use some sort of "non-destructive" routing in React so that the markup would not be destroyed, only hidden, when routing out of the page with Scheduler. Then no such workarounds are needed. That's what I would strongly recommend.


Post Reply