View Source LiveViewEvents.Notify (live_view_events v0.1.2)
Functions to send messages in the server including to live components and handle them.
Example
In our view, we are going to have two components. The first one is a Sender
that can send an event to whatever is being passed. Let's dig into the
implementation:
defmodule MyAppWeb.Components.Sender do
use MyAppWeb, :live_component
use LiveViewEvents
def mount(socket) do
socket = assign(socket, :notify_to, :self)
{:ok, socket}
end
def render(assigns) do
~H[<button type="button" phx-click="clicked" phx-target={@myself}>Send event</button>]
end
def handle_event("clicked", _params, socket) do
notify_to(socket.assigns.notify_to, :sender_event, :rand.uniform(100))
{:noreply, socket}
end
end
This component will send a :sender_event
message to whatever we pass to the notify_to
attribute. It sends a random number between 0 and up to 100 as parameter.
Let's dig into the receiver:
defmodule MyAppWeb.Components.Receiver do
use MyAppWeb, :live_component
use LiveViewEvents
def mount(socket) do
socket = assign(socket, :messages, [])
{:ok, socket}
end
def update(assigns, socket) do
socket = handle_info_or_assign(socket, assigns)
{:ok, socket}
end
def render(assigns), do: ~H[<ul><li :for={m <- @messages}><%= m %></li></ul>]
def handle_info({:sender_event, num}, socket) do
{:noreply, update(socket, :messages, &[num | &1])}
end
end
This component will receive messages and handle them in handle_info/2
because
it is using handle_info_or_assign/2
in their LiveComponent.update/2
.
It will add the received messages to socket.assigns.messages
and display
them. As the reader can see, it is pattern matching against :sender_event
messages.
When notify_to/3
is used, the message sent is a tuple containing the event name
as first element, and the params as second the second element.
Finally, let's take a look at what the live view template would need to look like for this to work:
<div class="contents">
<.live_component
module={MyAppWeb.Components.Sender}
id="sender"
notify_to={{MyAppWeb.Components.Receiver, "receiver"}}
/>
<.live_component module={MyAppWeb.Components.Receiver} id="receiver" />
</div>
In this template, we set notify_to
to the tuple {MyAppWeb.Components.Receiver, "receiver"}
.
The first element of the tuple is the live component module and the second is the id.
Optionally, the tuple can contain an extra first element that needs to be a PID. Though
this might not be useful in the application code (there are way better ways to send events
between processes), it is quite useful when testing. When testing a LiveView
,
it creates a new process for it. Its PID can be accessed through view.pid
.
Summary
Functions
Use this macro instead of the default assigns(socket, assign)
in
Phoenix.LiveComponent.update/2
.
notify_to/2
accepts a target and a message name. The target can be any of
notify_to/3
behaves like notify_to/2
but accepting some extra parameters as the third arguments.
In this case, the message sent would be a tuple with the message
as first element and params
as the
second one.
Functions
Use this macro instead of the default assigns(socket, assign)
in
Phoenix.LiveComponent.update/2
.
This will detect if Phoenix.LiveComponent.update/2
is being called
because of an event send with either notify_to/2
or notify_to/3
and handle it with Phoenix.LiveView.handle_info/2
. Otherwise,
it will assign the given assigns
to socket
.
If there is no Phoenix.LiveView.handle_info/2
defined in the
component, sending an event won't raise an error but if there is one
defined and it cannot handle the received message, it will.
Furthermore, if the handler returns anything that is not a tuple
{:noreply, socket}
, it'll raise an exception too.
Why using Phoenix.LiveView.handle_info/2
in components?
In one word: consistency. Messages coming from the client are
handled by LiveView.handle_event/3
in live views or by LiveComponent.handle_event/3
in live components.
Messages sent from the server are currently being handled by
LiveView.handle_info/2
in live views,
with no official way to do this but the hack this library is based on.
The hack is basically send an update with LiveView.send_update/3
and handle it in LiveComponent.update/2
.
notify_to/2
accepts a target and a message name. The target can be any of:
nil
would make it be a noop.:self
to send toself()
.- A PID.
- A tuple of the form
{Module, "id"}
to send a message to aLiveView.Component
in the same process. - A tuple of the form
{pid, Module, "id"}
to send a message to aLiveView.Component
in a different process.
The event send will take the form of {message, %{}}
.
notify_to/3
behaves like notify_to/2
but accepting some extra parameters as the third arguments.
In this case, the message sent would be a tuple with the message
as first element and params
as the
second one.