diff --git a/src/core/directives/collapsible-footer.ts b/src/core/directives/collapsible-footer.ts index e041fa096..57f24d707 100644 --- a/src/core/directives/collapsible-footer.ts +++ b/src/core/directives/collapsible-footer.ts @@ -72,6 +72,10 @@ export class CoreCollapsibleFooterDirective implements OnInit, OnDestroy { await this.calculateHeight(); + CoreDomUtils.onElementSlot(this.element, () => { + this.calculateHeight(); + }); + this.listenScrollEvents(); } diff --git a/src/core/services/utils/dom.ts b/src/core/services/utils/dom.ts index 2df0fcfc1..88215d904 100644 --- a/src/core/services/utils/dom.ts +++ b/src/core/services/utils/dom.ts @@ -220,6 +220,53 @@ export class CoreDomUtilsProvider { ); } + /** + * Runs a function when an element has been slotted. + * + * @param element HTML Element inside an ion-content to wait for slot. + * @param callback Function to execute on resize. + */ + onElementSlot(element: HTMLElement, callback: (ev?: Event) => void): void { + if (!element.slot) { + // Element not declared to be slotted. + return; + } + + const slotName = element.slot; + if (element.assignedSlot?.name === slotName) { + // Slot already assigned. + callback(); + + return; + } + + const content = element.closest('ion-content'); + if (!content || !content.shadowRoot) { + // Cannot find content. + return; + } + + const slots = content.shadowRoot.querySelectorAll('slot'); + const slot = Array.from(slots).find((slot) => slot.name === slotName); + + if (!slot) { + // Slot not found. + return; + } + + const slotListener = () => { + if (element.assignedSlot?.name !== slotName) { + return; + } + + callback(); + // It would happen only once. + slot.removeEventListener('slotchange', slotListener); + }; + + slot.addEventListener('slotchange', slotListener);; + } + /** * Window resize is widely checked and may have many performance issues, debouce usage is needed to avoid calling it too much. * This function helps setting up the debounce feature and remove listener easily.