-
-
Notifications
You must be signed in to change notification settings - Fork 364
[LiveComponent] Fix loadingDirectives match elements from nested components #1392
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[LiveComponent] Fix loadingDirectives match elements from nested components #1392
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for getting on this. Possible to add a test too - should be able to combine something from child.test.js
into loading.test.js
.
let matchingElements = [...element.querySelectorAll('[data-loading]')]; | ||
|
||
// ignore elements which are inside a nested "live" component | ||
matchingElements = matchingElements.filter((elt) => elt.closest('[data-controller~="live"]') === element); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We have a built-in mechanism for this we should use - it's elementBelongsToThisComponent
from dom_utils.ts
. We can pass the component
instance from LoadingPlugin.attachToComponent
into the callbacks, then into here so we can call that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think using the DOM will be better in term of performance, as we just manipulate Node element.. but that could be challenged. Do you want to use it for now ?
We could probably use only a CSS selector but i think we need to define this browser compatibility list before :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Test added @weaverryan
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for adding the test! I still think we should use elementBelongsToThisComponent()
. By not using it, we're adding "dangling code": we have just one part of the code that works differently than everywhere else. We would need a real, verified performance reason to do such a thing. And, except for cases where there actually are children (which is not most live components), the elementBelongsToThisComponent()
is basically just a call to element.contains()
- https://github.com/symfony/ux/blob/2.x/src/LiveComponent/assets/src/dom_utils.ts#L204
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Made changes, i cannot test locally for now, is this how you imagined it ?
@@ -2393,7 +2393,8 @@ class LoadingPlugin { | |||
} | |||
getLoadingDirectives(element) { | |||
const loadingDirectives = []; | |||
let matchingElements = element.querySelectorAll('[data-loading]'); | |||
let matchingElements = [...element.querySelectorAll('[data-loading]')]; | |||
matchingElements = matchingElements.filter((elt) => elt.closest('[data-controller~="live"]') === element); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am not sure about the use of the closest
function. closest
finds only one element, but in a live component you can have multiple elements with a loading attribute in nested element
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
closest is an ascending selector, it look the first parent "live controller"
let matchingElements = [...element.querySelectorAll('[data-loading]')]; | ||
|
||
// ignore elements which are inside a nested "live" component | ||
matchingElements = matchingElements.filter((elt) => elt.closest('[data-controller~="live"]') === element); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for adding the test! I still think we should use elementBelongsToThisComponent()
. By not using it, we're adding "dangling code": we have just one part of the code that works differently than everywhere else. We would need a real, verified performance reason to do such a thing. And, except for cases where there actually are children (which is not most live components), the elementBelongsToThisComponent()
is basically just a call to element.contains()
- https://github.com/symfony/ux/blob/2.x/src/LiveComponent/assets/src/dom_utils.ts#L204
cbf694f
to
c769ac4
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One minor tweak needed - thanks!
component.on('loading.state:started', (element: HTMLElement, request: BackendRequest) => { | ||
this.startLoading(element, request); | ||
component.on('loading.state:started', (element: HTMLElement, request: BackendRequest, component: Component) => { | ||
this.startLoading(component, element, request); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We already have the component
as the argument to attachToComponent
and we're attaching the loading.state.started
to that specific component. So o need for the new argument to the callback: we can use the component
variable already
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As i could not test, i did it in a defensive way :)
I'll remove it
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fix / rebased / rebuilded (style cannot test locally -- will fix this next week)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Think i did what you meant but not sure
1da752b
to
af3882c
Compare
af3882c
to
7867e44
Compare
Thanks Simon! |
Oh damn... i was pushing to rebase .... hope i did not mess on the go with things |
All good, I merged before you rebased. I did the rebasing ;) |
…ase 🚀 (weaverryan) This PR was squashed before being merged into the 2.x branch. Discussion ---------- [Live][Stimulus] Prepping the LiveComponent Stable Release 🚀 | Q | A | ------------- | --- | Bug fix? | no | New feature? | yes | Issues | None | License | MIT Hi! LiveComponents has, really, been quite stable for a long time, but it's kept its experimental status. Removing that is really about deciding that we'll protect backwards-compatibility. It's time to do that :). This is planned as the 2.15.0 release near the end of Feb (assuming we get the items below done before then). TODOs: * #1418 * Possibly remove Twig 2.x compat * #1428 * #1392 * Moving `Idiomorph` to a peer dependency would be great, but blocked by bigskysoftware/idiomorph#35 - **still need a tag** for the PR merge * #1426 as it may include some edge-case BC breaks. If there's anything else on your mind before stable, now is the time to mention it :). Cheers! Commits ------- 7932a9d [Live][Stimulus] Prepping the LiveComponent Stable Release 🚀
The elements with loading directives were used in all LiveController they were in.
This PR fixes that and restrict loadingDirective to the scope of the LiveContoller (and filter those belonging to nested / child components)