trestrantham

trestrantham

LiveView flash assigns not available in child LiveComponent

I have a LiveView that renders a LiveComponent via an leex template:

defmodule MyAppWeb.ThingEditView do
  use Phoenix.LiveView

  def mount(_params, _session, socket) do
    {:ok, socket}
  end

  def render(assigns) do
    MyLiveView.render("edit.html", assigns)
  end

  def handle_info({:update_thing, thing, thing_params}, socket) do
    case Thing.update_thing(thing, thing_params) do
      {:ok, thing} ->
        {:noreply,
         socket
         |> put_flash(:info, "Thing updated successfully.")
         |> push_redirect(to: Routes.live_path(socket, MyAppWeb.ThingEditView, thing))}

      {:error, %Ecto.Changeset{} = changeset} ->
        {:noreply, assign(socket, changeset: changeset)}
    end
  end
end

The template renders the LiveComponent like:

<%= live_component(@socket, MyAppWeb.MyLiveComponent) %>

When ThingEditView is rendered after the push_redirect above, I can see the flash message in MyAppWeb.ThingEditView’s socket.assigns.flash. I would then expect by passing socket into MyLiveComponent I would be able to pull out the flash message in the LiveComponent via live_flash(@flash, :info).

However, socket.assigns.flash is always an empty map when my LiveComponent is rendered. I never call live_flash/2 in the LiveView and would expect the flash message to remain in the socket assigns until I pull it out in my LiveComponent.

Is this the correct way to be thinking about flash with LiveView? Am I missing something that would enable to behavior I’m after?

Marked As Solved

sfusato

sfusato

My understanding is that the combo put_flash + plug :fetch_live_flash is a convenience that will make the flash messages available in your main live view under the assign flash. In order to have it available in other liveviews/components rendered in your main liveview, you would have to pass it further along as an assign.

<%= live_component(@socket, MyAppWeb.MyLiveComponent, flash: @flash) %>

Also Liked

jtormey

jtormey

This approach can also be abstracted out so that it doesn’t have to be repeated in every LiveView, using a helper module with on_mount/4 and attach_hook/4.

I’ve done this in the past:

defmodule MyAppWeb.LiveFlash do
  def on_mount(:default, params, _session, socket) do
    {:ok, attach_hook(socket, :flash, :handle_info, &handle_flash/2)}
  end

  def push_flash(key, msg) do
    send(self(), {:flash, key, msg}
  end

  defp handle_flash({:flash, key, msg}, socket) do
    {:halt, put_flash(socket, key, msg)}
  end

  defp handle_flash(_otherwise, socket) do
    {:cont, socket}
  end
end

Then, in my_app_web.ex:

  def live_view do
    quote do
      use Phoenix.LiveView,
        layout: {MyAppWeb.Layouts, :app}

      on_mount MyAppWeb.LiveFlash

      unquote(html_helpers())
    end
  end

  def live_component do
    quote do
      use Phoenix.LiveComponent

      import MyAppWeb.LiveFlash, only: [push_flash: 2]

      unquote(html_helpers())
    end
  end

Now calling push_flash/2 from a LiveComponent will make the parent LiveView render the flash :slight_smile:

KristerV

KristerV

very cool. i’m using phoenix 1.7 RC2+ (actually git master due to bugs) so had to make a few adjustments.

live_flash.ex

defmodule AppWeb.LiveFlash do
  import Phoenix.LiveView

  def on_mount(:default, _params, _session, socket) do
    {:cont, attach_hook(socket, :flash, :handle_info, &handle_flash/2)}
  end

  def push_flash(key, msg) do
    send(self(), {:flash, key, msg})
  end

  defp handle_flash({:flash, key, msg}, socket) do
    {:halt, put_flash(socket, key, msg)}
  end

  defp handle_flash(_otherwise, socket) do
    {:cont, socket}
  end
end

app_web.ex

  def live_view do
    quote do
      use Phoenix.LiveView,
        layout: {AppWeb.Layouts, :app}

      on_mount AppWeb.LiveFlash                          # add this line

      unquote(html_helpers())
    end
  end

  def live_component do
    quote do
      use Phoenix.LiveComponent

      import AppWeb.LiveFlash, only: [push_flash: 2]     # add this line

      unquote(html_helpers())
    end
  end

very clever, thanks @jtormey

chrismccord

chrismccord

Creator of Phoenix

Passing flash down as assigns is the way to go. Note, that you may want to pass it down as @parent_flash or similar as the nested components may have their own flash to display which you don’t necessary want to display on the parent.

Where Next?

Popular in Questions Top

sen
Hi All, I set a environment variables in dev.exs , like below code. when i start server, how can i set the ${enable} value? thanks. d...
New
sergio
In Ruby, I can go: User.find_by(email: "foobar@email.com").update(email: "hello@email.com") How can I do something similar in Elixir? ...
New
chrisalley
ExUnit now has describe blocks which is a welcome addition coming from RSpec. In the docs, it states that nested hierarchies of describe ...
New
jerry
Good day to you all. I have been struggling to get a query involving like and ilike to work. Can anyone assist me on this, please? pro...
New
stefanchrobot
What’s the safe way to decode a JSON string into a struct? I want to avoid calling String.to_atom. Jason.decode can give me a map with st...
New
hariharasudhan94
lets say i have a sample like a = 20; b = 10; if (a &gt; b) do {:ok, "a"} end if (a &lt; b) do {:ok, b} end if (a == b) do {:ok, "equa...
New
jaysoifer
Is there a way to rollback a specific migration and only that one (“skipping” all the other ones)? Would mix ecto.rollback -v 200809061...
New
pmjoe
I have a relationship of love and hate with Elixir. Lots of things are just absolutely right, but there are some things that are kind of ...
New
SoCreat
i’m a new one to elixir which editor can i use vs code? or atom? Thanks! :smiley:
New
yawaramin
In the Dialyzer docs ( dialyzer — OTP 29.0.2 (dialyzer 6.0.1) ), there is a way to turn off a specific warning for a function: -dialyzer...
New

Other popular topics Top

JeremM34
Hello, how can I check the Phoenix version ? Thanks !
New
ovidiubadita
Hey all, I discovered Elixir and I love it. I always wanted to learn a functional programming and I intended to go for Haskell, but afte...
New
AngeloChecked
What learn first? Rust or Elixir Hi Elixir community! I’m here because i want learn a new language. I’m a junior developer and mainly i ...
New
pmjoe
I have a relationship of love and hate with Elixir. Lots of things are just absolutely right, but there are some things that are kind of ...
New
alice
Hey, Just curious what are the main benefits of Elixir compared to Clojure? When is Elixir more useful than Clojure and vice versa? Th...
New
gausby
I asked this very same question on twitter and got some interesting feedback, but I thought it would be a good question to ask here as we...
1207 39297 209
New
bsollish-terakeet
Credo is smart enough to check for (something like) this: assert length(the_list) == 0 with this response: Checking if an enum is empt...
New
ashish173
I am using Ecto timestamps with postgres, I can see the timestamps() use the :naive_dateime but for my use case I wanted to store the ti...
New
hariharasudhan94
I would like to know what is the best IDE for elixir development?
New
openscript
Hello! Sorry for this astonishing simple question, but I’m really stuck. I try to set up the intellij-elixir plugin, but I don’t know ho...
New

Latest on Elixir Forum

We're in Beta

About us Mission Statement