diff --git a/core/src/utils/helpers.ts b/core/src/utils/helpers.ts index f35dca35bd..1d617f2277 100644 --- a/core/src/utils/helpers.ts +++ b/core/src/utils/helpers.ts @@ -5,11 +5,23 @@ import { Side } from '../interface'; declare const __zone_symbol__requestAnimationFrame: any; declare const requestAnimationFrame: any; +/** + * Waits for a component to be ready for + * both custom element and non-custom element builds. + * If non-custom element build, el.componentOnReady + * will be used. + * For custom element builds, we wait a frame + * so that the inner contents of the component + * have a chance to render. + * + * Use this utility rather than calling + * el.componentOnReady yourself. + */ export const componentOnReady = (el: any, callback: any) => { if (el.componentOnReady) { - el.componentOnReady().then(callback); + el.componentOnReady().then((resolvedEl: any) => callback(resolvedEl)); } else { - callback(); + raf(() => callback(el)); } } diff --git a/core/src/utils/test/ready.spec.ts b/core/src/utils/test/ready.spec.ts new file mode 100644 index 0000000000..f71e560011 --- /dev/null +++ b/core/src/utils/test/ready.spec.ts @@ -0,0 +1,42 @@ +import { componentOnReady } from '../helpers'; + +describe('componentOnReady()', () => { + it('should correctly call callback for a custom element', (done) => { + customElements.define('hello-world', class extends HTMLElement { + constructor() { + super(); + } + }); + + const component = document.createElement('hello-world'); + componentOnReady(component, (el) => { + expect(el).toBe(component); + done(); + }) + }); + + it('should correctly call callback for a lazy loaded component', (done) => { + const cb = jest.fn((el) => { + return new Promise((resolve) => { + setTimeout(() => resolve(el), 250); + }); + }); + + customElements.define('hello-world', class extends HTMLElement { + constructor() { + super(); + } + + componentOnReady() { + return cb(this); + } + }); + + const component = document.createElement('hello-world'); + componentOnReady(component, (el) => { + expect(el).toBe(component); + expect(cb).toHaveBeenCalledTimes(1); + done(); + }) + }); +});