Set a flash message from a LiveComponent
The documentation for put_flash/3
in the Phoenix LiveView docs states that the @flash
assign is only copied to the parent LiveView if the component calls push_navigate/2
or push_patch/2
.
So if we want to set a flash message without navigation, we can use message passing to send a flash message which the parent LiveView will set on behalf of the component.
A LiveComponent is run in the same process as the parent LiveView, so we can send a message to self()
and listen to this on the parent.
defmodule MyComponent do
use MyAppWeb, :live_component
def handle_event("my-event", _params, socket) do
send(self(), {:put_flash, [:info, "Flash message"]})
{:noreply, socket}
end
end
In the parent LiveView we can listen for this message and set the flash.
defmodule MyLiveView do
use MyAppWeb, :live_view
def handle_info({:put_flash, [type, message]}, socket) do
{:noreply, put_flash(socket, type, message)}
end
end
To make this more generic, you can add the handle_info/2
callback in your web.ex
file.
For more information on how to handle global broadcasts in LiveView (and what I’m doing with the @before_compile), see How to respond to global broadcasts in Phoenix LiveView.
defmodule MyAppWeb do
def live_view do
quote do
@before_compile {MyAppWeb, :live_view_handle_info_warning}
def handle_info({:put_flash, [type, message]}, socket) do
{:noreply, put_flash(socket, type, message)}
end
end
defmacro live_view_handle_info_warning(_env) do
quote do
def handle_info(payload, %{view: view} = socket) do
Logger.warning(
"undefined handle_info in #{inspect(view)}. Unhandled message: #{inspect(payload)}"
)
noreply(socket)
end
end
end
end
end