I have a Liveview component with a navbar and components to display/hide as tabs, aka breadcumbs. I also want to highlight the link tag of the active breadcumb.
Say the live
endpoint "/crumbs" renders the following Liveview:
# MyAppWeb.CrumbsLive
def renders(assigns) do
~H"""
<section>
<Nav active={@active} display={@display} />
<Elt1.render />
<Elt2.render />
...
</section>
"""
end
Each tab is a component with a unique id:
# MyAppWeb.Elt1
use Phoenix.Component
def MyApp.Elt1 do
def render(assigns) do
~H"""
<div id="elt-1">...</div>
"""
end
end
The navbar displays the link to the components. The link will be a patch
to the url below as parameter, so we will invoque handle_params
(cf the guide https://hexdocs.pm/phoenix_live_view/deployments.html)
"/crumbs?display=elt-i"
use the
phx-mount
dataset to display some folder on mount (available also on static views, not only LVs).use
:html
to have access to the verified routes
#MyAppWeb.Nav
use MyAppWeb, :html
attr :active, :any #Function
attr :display, :any #Function
def render(assigns) do
<nav phx-mount={@display.("#elt-1")}>
...
<.link
class={@active.("#elt-i")}
phx-click={@display.("#elt-i")}
patch={~p"/crumbs?display=elt-i1"}
>
Elt i
</.link>
...
</nav>
end
We pass 2 functions in the assigns:
the first prop
active
is a function that takes the id of the element of the target location. It will add some highlighting classes to the matching location: a simple conditional concatenation of classes if the view given by the query string matches the current location.the second prop
display
is a function that takes the id of the element of the target location. It will simply pipeJS.hide
of all the ids butJS.show
the desired one.
A click on the link will be captured by handle_params/3
in the Liveview. We build the props there. Since they depend upon the location, they will be updated into the socket assigns, and this change will render the new UI.
#MyAppWeb.CrumbsLive
def handle_params(q_string, _uri, socket) do
# list of ids of the tabs/elements
nav_elts = ['#elt-1', '#elt-2',..]
base = "some classes"
styled = "highlighting classes"
view =
case map_size(q_string) do
# on mount
0 -> "#elt-1"
_ -> "#" <> Map.get(q_string, "display")
end
active = fn current -> [base, current === view && styled] end
display = fn current ->
nav_elts
|> Enum.filter(&(&1 !== current))
|> Enum.reduce(%JS{}, fn elt, acc ->
acc |> JS.hide(to: elt)
end)
|> JS.show(to: current)
end
{:noreply, assign(socket, active: active, display: display)}
end
Top comments (0)