Front-end changes only
In order to use front-end only options I advise the following.
- We would need to store state for that collapsible element.
- We would need to restore collapsible state of that element on every socket channel update
For simplicity I will use plain javascript.
We need to modify button, and write function to store state (I used simple localStorage)
<a class="collapse_trigger" onclick="memoizeCollapsibleState()">...</a>
<script type="text/javascript">
function memoizeCollapsibleState() {
if (!localStorage.getItem('collapsibleState')) {
localStorage.setItem('collapsibleState', true)
} else {
localStorage.removeItem('collapsibleState')
}
}
</script>
afterwards we need to write function that will restore that state from localstorage
function restoreCollapsibleState() {
var collapsibleEl = document.getElementById('collapseExample');
if (localStorage.getItem('collapsibleState')) {
collapsibleEl.classList.add('is-active')
}
}
And final moment we need to bind that function to phoenix_live_view
socket update, we need to do it right after window has been loaded.
window.onload = init;
function init() {
liveSocket.getSocket().channels[0].onMessage = function (e, t, n) {
setTimeout(restoreCollapsibleState, 10)
return t
}
}
The purpose of setTimeout
function is that socket updates is async operation, and we need to add some delay in order to have collapsible state restored. 10ms seems to be ok, but we can change it to any other debounce function, I just used it for simplicity, consider this is as proof of concept
Back-end changes only
I just made an example with default live phoenix structure
mix phx.new my_app --live
Added bootstrap to it (but I think bulma follows mostly the same rules)
And modified phoenix live template to the following
<div class="collapse <%= if (@results && String.trim(@query) != ""), do: "show", else: "" %>" id="collapseExample">
<div class="card card-body">
<%= for {app, _vsn} <- @results do %>
<p value="<%= app %>"><%= app %></p>
<% end %>
</div>
</div>
so if there are any results and query is not empty thus will not be ever collapsed.
For your case I think it will be slightly the same
<a class="collapse_trigger">...</a>
<div class="is-collapsible <% if (@results && String.trim(@query) != "") do: "is-active", else: "" %>">
# content
</div>