support icon indicating copy to clipboard operation
support copied to clipboard

Cannot add items into container after remove previous using `destroy`

Open chuckn0rris opened this issue 1 year ago • 2 comments

Forum post

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')

chuckn0rris avatar Dec 11 '24 10:12 chuckn0rris

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

chuckn0rris avatar Dec 11 '24 10:12 chuckn0rris

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();
        }
    }

ExtAnimal avatar Dec 11 '24 11:12 ExtAnimal