Skip to content

Commit

Permalink
[LiveComponent] Fix - data-loading expressions not working on root node
Browse files Browse the repository at this point in the history
  • Loading branch information
WebMamba committed Dec 9, 2023
1 parent bb32456 commit 346dae7
Show file tree
Hide file tree
Showing 3 changed files with 43 additions and 2 deletions.
6 changes: 5 additions & 1 deletion src/LiveComponent/assets/dist/live_controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -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');
}
Expand Down
10 changes: 9 additions & 1 deletion src/LiveComponent/assets/src/Component/plugins/LoadingPlugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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');
}
Expand Down
29 changes: 29 additions & 0 deletions src/LiveComponent/assets/test/controller/loading.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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) => `
<div ${initComponent(data)} data-loading="addClass(opacity-20)">
<span>I like: ${data.food}</span>
<button data-action="live#$render">Re-Render</button>
</div>
`);

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) => `
<div ${initComponent(data)}>
Expand Down

0 comments on commit 346dae7

Please sign in to comment.