Both layouts for liveview and normal view renders when using live_render on root.html.leex

Hi,

I’m working on an app and wanted the navbar to use a liveview or a live component.
Since I rather not duplicate the code, I’ve tried putting the navbar liveview on root.html.leex and it seem to render fine and working.
However, when I went on to test flashes, I supported that flashes will show both above the navbar and in the main body as well.

Turns out that live.html.leex is being rendered twice, one that wraps the navbar, and the other wrapping the body.
Here’s a screenshot for reference

I’ve thought of trying using live component as well but since the root template doesn’t have @socket, it’s pretty much impossible to render a live component.

Has anyone encountered this before?
Any recommendations to get rid of the flash for the navbar is welcomed.

Thanks

1 Like

Hello,

let’s imagine you have 3 files:

  • root.html.leex
  • app.html.eex
  • live.html.leex

In your router, in the brower pipeline you can set

  pipeline :browser do
    plug(:put_layout, {DropShippingWeb.LayoutView, :app})
    plug(:put_root_layout, {DropShippingWeb.LayoutView, :root})
  end

Basically it will set the default root layout as root.html.leex and the default layout as app.html.eex.
Then, when you need to use live_view (so basically when you don’t have your @conn) you will write things like:

defmodule YourLiveView do
  use Phoenix.LiveView, layout: {MyAppWeb.LayoutView, "live.html"}

  ...
end

Now in the root.html.leex you should put general things, like menus, footer etc.
In the app.html.eex you can simply write your get_flash/2 and in the live.html.leex you ca use @flash.

So what happen when using layout:

  • in default case : use root layout → use app layout → render the view
  • when specifying the layout in liveview → use general layout → use live layout → render the view

Your double flash messages should disappear.

There is also other methods, describe here Phoenix.LiveView — Phoenix LiveView v0.15.4. Where you can set the layout in the router.

Have a great day :wink:

5 Likes

Thanks for the suggestion!

I think I might found a easier way by adding an empty layout instead

# /lib/app_web/templates/layout/navbar.leex

<%= @inner_content %>
# /lib/app_web/lib/navbar_live/navbar_live.ex

def mount(_params, _session, socket) do
    {:ok,
     socket,
     layout: {ArchiveWeb.LayoutView, "navbar.html"}}
end

I’ll keep your reference in mind too just in case what I found didn’t work.

1 Like