Support Forum
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();
I've created this ussue to make public method for this
https://github.com/bryntum/support/issues/38
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)
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} />;
};
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();
}
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();
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()
?
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.