I’m experiencing some undesirable behaviour in Liveview when I try to use a JS.dispatch
command in a chain that includes a JS.push
.
I have 3 main elements on a liveview. A block of filters, a button that shows or hides the filters and a list of items returned as per the filters.
# the filter element
<.form
for={@available_filters}
id="filters-form"
data-hide-filter-block={
JS.hide(to: "#filters-form")
|> JS.dispatch("myapp:change-text", to: "#show-filters-button")
}
>
#stuff
<./form>
# the button
<button
class="btn"
id="show-filters-button"
phx-click={JS.dispatch("myapp:toggle-filter-form")}
>
<%= IO.inspect(Time.utc_now()) %>
</button>
# the clickable element
<div
id={"item_#{item.id}"}
phx-click={
JS.push("select-item", value: %{item: item.id})
|> JS.exec("data-hide-filter-block", to: "#filters-form")
}
>
#stuff
</div
# the event listener to change the text
window.addEventListener("myapp:change-text", (event) => {
event.target.textContent= "Show Filters";
});
The button has a JS.dispatch()
event triggering an event listener that hides/shows the filters as appropriate and changes the text of the button to “ShowHide Filters”. This works fine.
When an Item is clicked I send an event to the server to retrieve the item and I want to hide the filters then change the text of the button. When I try to use the JS.dispatch
command in the same chain as the JS.push
the odd behaviour happens.
The event listener targeted by JS.dispatch
is triggered successfully and executes its code, hiding the filters and changing the button text. The button then immediately reverts to its “default” state and the filters re-appear. It all happens just quickly enough to see the visual transition.
I’ve tried a few different variations of issuing the JS.dispatch command, always producing the same result. The code above is the current code state.
I know that the filter block is not being re-rendered in the liveview sense because the timestamp on the button text stays the same and it does not appear in the diff on the websocket message, nor is the filter function component being re-rendered due to an assigns change.
For the life of me I can’t figure out what is going on. What I can see is:
- The item gets clicked
- The server event is handled successfully
- The event listener is executed
- The filters are hidden and the button text changes very briefly
- The filters are visible and button text has reverted to its initial state.
I can’t see any “special” rules on the JS.dispatch()
documentation and other JS commands like hide/show/add_class aren’t producing similar behaviour. Likewise, if I remove the JS.push()
then the JS.dispatch()
works as expected.
Have I missed something obvious?
EDIT:
Since posting I’ve also noticed that the above is only true for the first click of an individual item
. Subsequent clicks produce the expected behaviour.