Hi,
I have something like this in router, different LiveViews using the same layout:
live_session :kanban,
on_mount: TodoWeb.Kanban,
layout: {TodoWeb.Layouts, :kanban} do
live "/boards/:id", BoardLive
live "/boards/:id/settings", BoardSettingsLive
end
The shared layout has a sidebar that is toggled based on the sidebar_open
assign, and it is initialized by the on_mount
function inside the TodoWeb.Kanban
module.
defmodule TodoWeb.Kanban do
def on_mount(:default, _params, _session, socket) do
socket =
socket
|> assign(sidebar_open: true)
{:cont, socket}
end
end
This way I do not have to assign sidebar_open
in every LiveView that uses the layout, but I still have to define the below handle_event
callback inside every LiveView that uses the layout (BoardLive
and BoardSettingsLive
in this case), is there a way to avoid this repetition?
def handle_event("toggle_sidebar", _unsigned_params, socket) do
{:noreply, assign(socket, sidebar_open: !socket.assigns.sidebar_open)}
end
See attach_hook/4 for one way to do it. You could also make your sidebar a LiveComponent and render it in the layout, though I personally use attach_hook
.
Though to be clear, I use this for the current path. You’re generally better off using JS commands for managing UI-only state like if a sidebar is open or not.
1 Like
Thanks, really JS commands seem to make more sense in my case, but it was good to know about attach_hook/4
for future needs.
1 Like
If you generated your project with phx.new
then you probably have a filed called todo_web.ex
that has code that looks like this:
def live_view do
quote do
use Phoenix.LiveView, layout: MomoWeb.live_view_layout()
end
end
which is used in your LiveView with use
, like this:
use TodoWeb, :live_view
So you could just add your handle_event
function inside the quote block, if you wanted.
If that starts getting too long, you could make a new file lib/todo_web/sidebar_toggling.ex
or something (your choice of name), that looks like this:
defmodule TodoWeb.SidebarToggling do
defmacro __using__(_) do
quote do
def handle_event("toggle-sidebar", _, socket) do
socket
|> update(:sidebar_open, &Kernel.!/1)
|> then(&{:noreply, &1})
end
end
end
end
and then back in the live_view
quote block, just add 1 line:
def live_view do
quote do
# ....
use TodoWeb.SidebarToggling
end
end
I am not saying you should do this. Using attach_hook
is often best practice for stuff like this. I’m just making you aware of this using
trick, which can be a nice way of splitting up large Elixir modules, or of sharing common code among many modules, even outside of LiveView/Phoenix world.
1 Like