Closed bastien70 closed 1 year ago
Hi @bastien70!
I think the longer answer to this is that we need a smarter re-render system, which is something I've been thinking about for awhile. The problem is that, when you expand an item, some CSS classes are probably added to "expand" that element. Then, on re-render, those CSS classes are missing from the Twig code, so LiveComponents removes them. We don't want that :).
In theory, we could "monitor" for any custom changes made by external JavaScript and be sure to not "undo" those on re-render.
That doesn't help you right now, so let's think of a shorter-term solution :). One idea: create a custom Stimulus controller. Use the hooks system to listen on render:started
. This is triggered right after an Ajax call has finished, but before it's been applied to the page. The idea would be to "detect" which item is currently open and save it to some local variable / property on your controller. Then, listen again to render:finished
and "re-open" that item - e.g. trigger a click on it or manually re-add the classes it needs. However, it's very possible that this would cause the item to quickly close then re-open again... so we'll need to see if it works in practice. We could also add some way in the render:started
hook to modify the HTML that will be applied so that you could add the classes there. Or, we may need some hooks inside of morphdom (the library that applies the "diff" of the latest html onto your component) so that you could run some code whenever an individual "element" is being updated. That would allow you to see that the existing element is one that is open, and add the necessary classes to the "new" element so that they're not removed.
Let me know if any of this helps :)
Hey Ryan!
Indeed, a "show" class is added on the div carrying the "collapse" class when you click on it (and disappears when you click on it again).
I have never used a hook before, but I will try tomorrow with pleasure!
I had also thought of an update idea, I don't know if it's easily added to the library, but a system with a Twig tag that would allow you to define specific places not to be updated, which could be more efficient than the "data-live-ignore" attribute which is effective for the entire element.
For example :
<li class="list-group-item" data-bs-toggle="collapse" data-bs-target="#sous_dossier" aria-expanded="false" aria-controls="sous_dossier">
<div class="d-flex justify-content-between align-items-center" role="button">
<span class="fs-4">My title</span>
<span class="badge bg-warning rounded-pill"> </span>
</div>
{% apply data_live_ignore %}
<div id="sous_dossier" class="collapse">
{% endapply %}
Collapsed content here !
</div>
</li>
Here, we would have the "apply data_live_ignore" tag that I could assign only to the opening of the element that will contain the class that will be added/removed.
And so when refreshing, this part should not be refreshed.
But I imagine that this kind of thing must be complex to set up?
Hey it's me! (Mariooo)
I am doing the custom controller with the hooks.
The problem is that the render:started
seems to fire after the divs uncollapse.
For example, I have an element that is collapsed, and so the div has class collapse
and class show
.
Except that at render:started
, everything uncollapses
directly before the render:started
custom script starts, and therefore my divs that had the show
class no longer have it at this moment, that's odd
Update: Mmh no actually it's the collapsed div in which I add a collection element that uncollapses before the started. The others that were collapsed do keep the show
class during render:start
.
So I just have to retrieve from which div there was a triggered event, allowing me to also add the show
class to it.
Status updates to follow :D
Update 2 : Ok so I confirm that I can put back in collapse show
the div other than the one for which I add an element.
I'm still looking for a way to find from which div an Ajax request is triggered, allowing me to go back to the collapsed element and add the show
class to it at the end, but impossible
Here is the current script :
// assets/controllers/some-custom-controller.js
// ...
import { Controller } from '@hotwired/stimulus';
import { getComponent } from '@symfony/ux-live-component';
export default class extends Controller {
async initialize() {
this.component = await getComponent(this.element);
let collapsedElementsIds = [];
this.component.on('render:started', (component) => {
// console.log(component);
collapsedElementsIds = [];
document.querySelectorAll('.show').forEach(function (element) {
collapsedElementsIds.push(element.id);
});
// do something after the component re-renders
});
this.component.on('render:finished', (component) => {
collapsedElementsIds.forEach(function(element) {
document.getElementById(element).classList.add('show');
})
// do something after the component re-renders
});
}
}
Update 3 : In the meantime, I found a "hacky" way to put back in "collapse show" the div on which I add or delete an element.
In my component, I added a collapseId
property. And while adding/removing an element, I save in this property the ID of the element responsible for the action.
Then in the Twig file, I create a condition that checks that the collapseId
property is equal to the current element's ID, in which case, I add the show
class to it.
And in combination with the custom controller, it does the job.
But actually, we still have this little closing/opening
effect which isn't very pretty, which is a shame, but I imagine that I can't do better
Hello, I'm using LiveComponent to render an hardcore form with a lot of collections.
This form has collections inside collapsed div. When clicking the button to "add" or "remove" a collection item, the item is added/removed but all is "uncollapsed".
Example :
https://user-images.githubusercontent.com/53140475/220677572-1852e200-3e9e-4e8b-bd86-7109fbf66755.mp4
Unfortunately, I cannot add "data-live-ignore" in the div containing the collapsed content since otherwise the buttons allowing to add/remove an element from a collection will no longer refresh the fields.
I had another idea which was to set up a system that would save in the entities whether it's collapsed or not, and at refresh, would allow me to put everything back as it should be, but I find it restrictive, and I wonder if there isn't a better way?
This is how I render the form :
And in the component, my two liveAction to add or remove an item :
Thanks for your help!