support
support copied to clipboard
Cannot add items into container after remove previous using `destroy`
Reproduced in inline demo here https://bryntum.com/products/gantt/docs/api/Core/widget/Container
Make container global
window.container = new Container({
In console destroy save button
container.widgetMap.save.destroy()
And try to add new item. Any item, I just copied save btn config
container.add({
type : 'button',
text : 'Save',
cls : 'b-raised',
onClick : () => {
const name = container.getWidgetById('name').value,
score = container.getWidgetById('score').value;
if (score > 1000) {
Toast.show('New highscore!');
}
else {
Toast.show(`Saving ${name}s score, which was ${score}`);
}
}
})
Error
Uncaught TypeError: Cannot read properties of undefined (reading 'classList')
Take care of focus after removing item inside a container, if focused item removed. For example, in case focused item removed, it may close popup that contain removed items because of losing focus
The issue is that destroy just destroys with no regard to who owns that component.
Destroying a Container's child, just leaves the Container owning a destroyed child.
Widget's doDestroy needs:
doDestroy() {
const
me = this,
{
preExistingElements,
element,
adopt,
_refListeners,
_rootElement,
eventRoot,
ownedWidgets
} = me;
if (Fullscreen.element === element) {
Fullscreen.exit();
}
if (_refListeners) {
Object.values(_refListeners, un => un());
me._refListeners = null;
}
if (element) {
const sharedTooltip = !me._tooltip && _rootElement &&
Widget.Tooltip?.getSharedTooltip(_rootElement, eventRoot, true);
// If we are current user of the shared tooltip, hide it
if (sharedTooltip?.owner === me) {
sharedTooltip.owner = null;
sharedTooltip.hide();
}
me.onExitFullscreen();
// If we get destroyed very quickly after a call to show,
// we must kill the timers which add the realign listeners.
me.clearTimeout('scrollListenerTimeout');
me.clearTimeout('resizeListenerTimeout');
// Remove listeners which are only added during the visible phase.
// In its own method because it's called on hide and destroy.
me.removeTransientListeners();
if (me.floating || me.positioned || me.positionable) {
// Hide without animation, if we have been shown, destruction is sync
me.isPainted && me.hide(false);
}
else {
me.revertFocus();
}
// If we are inside a Container, that Container cannot own a destroyed Widget
me.parent?.remove(me);
// Any owner cannot own a destroyed Widget
me.owner = null;
ResizeMonitor.removeResizeListener(element.parentElement, me.onParentElementResize);
ResizeMonitor.removeResizeListener(element, me.onElementResize);
// Remove elements *which we own* on destroy,
if (adopt) {
for (let nodes = Array.from(element.childNodes), i = 0, { length } = nodes; i < length; i++) {
const el = nodes[i];
// If it's not preexisting, and not the floatRoot, remove it
if (!preExistingElements.includes(el) && el !== me.floatRoot) {
el.remove();
}
}
element.className = me.adoptedElementClassName;
element.style.cssText = me.adoptedElementCssText;
}
me.dragEventDetacher?.();
me.dragOverEventDetacher?.();
me.dragGhost.remove();
}
me.connectedObserver?.disconnect();
super.doDestroy();
// Destroy widgets which have registered themselves as being owned by us
ownedWidgets && Object.values(ownedWidgets).forEach(w => w.destroy?.());
// When only shared tooltip + its two tools + ripple remains
// (no eventRoot if not appended to DOM)
eventRoot && Promise.resolve().then(() => {
// Don't evaluate this during destruction since it walks up the widget hierarchy and may trigger processing
// such as recompose
if (!Object.values(Widget.identifiable.idMap).some(isSingletonWidget)) {
GlobalEvents.detachFocusListeners(eventRoot);
}
});
// Only remove our element after full destruction is done
if (!adopt) {
element.remove();
}
}