I have a menu within a LiveView that I am hiding/unhiding based on a boolean that is toggled on button click. I also have a chat box that auto-scrolls downward as new items are added, via scrollIntoView
in a Hook.
The problem: when I click the menu button to toggle the menu, the chatbox scroll position gets sent to the top of the box.
Notably (and unexpectedly), phx-update="ignore"
on the div containing the chat messages does not prevent this behavior, and is not really an option as new messages are added via a handle_info
in the LiveView, necessitating phx-update="append"
.
One hacky fix would be to scroll the chatbox to the end every time the menu is toggled, but there has to be a better way Thoughts appreciated!
Code below (note, interstitial/irrelevant elements removed)
The parent LiveView:
<div>
<!-- In root LiveView -->
<button id="toggle-menu" phx-click="toggle_menu"></button>
<%= if @show_menu do %>
<%= link "Some link", to: "/some_link" %>
<% end %>
<!-- The chat component -->
<%=
live_component @socket,
MyAppWeb.PageLive.ChatComponent,
id: "chatbox-section",
messages: @messages
# etc
%>
</div>
The toggle menu click event:
def handle_event("toggle_menu", _params, socket) do
{:noreply, assign(socket, :show_menu, !socket.assigns.show_menu)}
end
The chat LiveComponent:
<section>
<div id="chatbox-feed" phx-update="append">
<%= for message <- @messages do %>
<div id="msg-<%= message.id %>"
phx-hook="NewMessage"
phx-update="ignore"
>
<div class="msg-info-name">
<%= message.username %>
</div>
<div class="msg-text">
<%= message.text %>
</div>
</div>
<% end %>
</div>
</section>
The message hook:
Hooks.NewMessage = {
mounted() {
// Scroll to this message
this.el.scrollIntoView({block: "end"});
}
}