Hi guys.
I’m currently working with the new LV JS API and it’s pretty cool. However i have a case where i need to trigger transitions of html elements from the server side. e.g.: A Notification that pops up after the last action was verified by the backend. Something that happens quite often.
I came up with a solution with a hook that triggers the transition by clicking on a hidden button.
Here a minimal example in surface
:
LV template
...
<Notification id="notify-fail"
type="error"
title={@notitication}
message={@message}/>
<Submit/>
...
LV callback
def handle_event("submit", params, socket) do
socket = if valid?(params) do
redirect(socket, to: "/foo")
else
socket
|> assign(title: "Something went wrong", message: "Pls check your foo")
|> Notification.open("notify-fail")
end
{:noreply, socket}
end
Notification Component
defmodule Notification do
use Surface.LiveComponent
alias Phoenix.LiveView.JS
prop message, :string
prop title, :string
def render(assigns) do
~F"""
<div id={@id} class="..." :hook="Notification">
<button id={@id <> "-trigger"} type="button" hidden :on-click={__MODULE__.show(@id)}></button>
{!-- some template stuff with @message and @string --}
</div>
"""
end
# clientside open
def show(id, js \\ %JS{}),
do: JS.show(js, to: "##{id}", transition: {"ease-out duration-300", "opacity-0", "opacity-100"})
# serverside open
def open(socket, id) do
socket |> push_event("open", %{id: id})
end
...
end
Notification Hook
...
mounted() {
this.handleEvent("open", ({id}) => {
if(id == this.el.id){
this.el.querySelector(`#${id}-trigger`).click()
}
})
}
...
Imo this solution seems like a dirty workaround because it created the necessity of writing an extra hook as well as providing two additional functions in the module doing basically the same thing . Will there be a feature handling this behaviour? Or do you know a better way of solving this issue?
greets