From 346dae743eb62e4920f5d524043748aa5b351f4a Mon Sep 17 00:00:00 2001 From: Matheo Daninos Date: Sat, 9 Dec 2023 14:19:11 +0100 Subject: [PATCH] [LiveComponent] Fix - data-loading expressions not working on root node --- .../assets/dist/live_controller.js | 6 +++- .../src/Component/plugins/LoadingPlugin.ts | 10 ++++++- .../assets/test/controller/loading.test.ts | 29 +++++++++++++++++++ 3 files changed, 43 insertions(+), 2 deletions(-) diff --git a/src/LiveComponent/assets/dist/live_controller.js b/src/LiveComponent/assets/dist/live_controller.js index 8bea5c1985e..4a644fe4728 100644 --- a/src/LiveComponent/assets/dist/live_controller.js +++ b/src/LiveComponent/assets/dist/live_controller.js @@ -2392,7 +2392,11 @@ class LoadingPlugin { } getLoadingDirectives(element) { const loadingDirectives = []; - element.querySelectorAll('[data-loading]').forEach((element => { + let matchingElements = element.querySelectorAll('[data-loading]'); + if (element.hasAttribute('data-loading')) { + matchingElements = [element, ...matchingElements]; + } + matchingElements.forEach((element => { if (!(element instanceof HTMLElement) && !(element instanceof SVGElement)) { throw new Error('Invalid Element Type'); } diff --git a/src/LiveComponent/assets/src/Component/plugins/LoadingPlugin.ts b/src/LiveComponent/assets/src/Component/plugins/LoadingPlugin.ts index 2fa85419737..0c26dae28b1 100644 --- a/src/LiveComponent/assets/src/Component/plugins/LoadingPlugin.ts +++ b/src/LiveComponent/assets/src/Component/plugins/LoadingPlugin.ts @@ -155,7 +155,15 @@ export default class implements PluginInterface { getLoadingDirectives(element: HTMLElement|SVGElement) { const loadingDirectives: ElementLoadingDirectives[] = []; - element.querySelectorAll('[data-loading]').forEach((element => { + let matchingElements = element.querySelectorAll('[data-loading]'); + + // querySelectorAll doesn't include the element itself + if (element.hasAttribute('data-loading')) { + // add element at the beginning of matchingElements + matchingElements = [element, ...matchingElements]; + } + + matchingElements.forEach((element => { if (!(element instanceof HTMLElement) && !(element instanceof SVGElement)) { throw new Error('Invalid Element Type'); } diff --git a/src/LiveComponent/assets/test/controller/loading.test.ts b/src/LiveComponent/assets/test/controller/loading.test.ts index 7ba5f3ec768..2d6448df2ea 100644 --- a/src/LiveComponent/assets/test/controller/loading.test.ts +++ b/src/LiveComponent/assets/test/controller/loading.test.ts @@ -48,6 +48,35 @@ describe('LiveController data-loading Tests', () => { expect(getByTestId(test.element, 'loading-element')).not.toBeVisible(); }); + it('executes basic loading functionality on root element', async () => { + const test = await createTest({food: 'pizza'}, (data: any) => ` +
+ I like: ${data.food} + +
+ `); + + test.expectsAjaxCall() + .serverWillChangeProps((data: any) => { + // to help detect when rendering is done + data.food = 'popcorn'; + }) + // delay so we can check loading + .delayResponse(50); + + // wait for element to hide itself on start up + await waitFor(() => expect(test.element).not.toHaveClass('opacity-20')); + + getByText(test.element, 'Re-Render').click(); + // element should instantly be visible + expect(test.element).toHaveClass('opacity-20'); + + // wait for loading to finish + await waitFor(() => expect(test.element).toHaveTextContent('I like: popcorn')); + // loading element should now be hidden + expect(test.element).not.toHaveClass('opacity-20'); + }); + it('takes into account the "action" modifier', async () => { const test = await createTest({}, (data: any) => `