LiveView and "dead" views helpers compatibility when used side by side

I’m adopting LiveView for an existing project. The idea is to use it for new functionality instead of rewriting existing stuff.

In general, my page templates look like this:

<%= sidebar do %>
  <!-- some page specific sidebar contents -->
  <%= link_to(@conn, Routes.foo_path, :show) do %>
    Foo!
  <% end %>
<% end %>
<main id="contents">
  <!-- the view inner contents -->
</main>

sidebar is just a helper function I use to render the sidebar shared template. The sidebar can be omitted for some views or have specific html, so I declare it in page specific templates. This means that a live or regular view template has to declare it.

In regular templates, I would use helpers like Routes.foo_path(@conn, :show, @item.id), and I do that a lot in shared templates. The issue is that in liveview the @conn isn’t available, and while I could pass MyApp.Endpoint instead, there are some helpers that require the conn for context, like phoenix_active_link’s active_link to add an active class if the current path matches the one from the link.

There’s also helpers that, while they work with both a conn and a socket, are troublesome to call without knowing which one it’s being passed on:

<%= if can?(@conn, :use_mod_tools) do %> <-- @conn is not available in live views,
                                             but @socket is not available in regular views,
                                             how to unify this?
  ...
<% end %>

So, my questions:

  • Is anybody using liveview in combination with regular views?
  • If so, how do you write shared templates/helpers that work in both contexts?
2 Likes

When using helper function like sidebar which is used in different templates, you can add a util file on the live directory that contains the common helper function.
i.e `lib/my_app_web/live/util.ex

def sidebar do
  <!-- some page specific sidebar contents -->
end
end

Alias the Util module to the LiveModules whose template will use the sidebar helper function. With this, you can get rid of the regular views since you don’t have to define the helper functions there.

By using MyApp.Endpoint , phoenix will always know how to interpret it. Most times it’s preferable if you are not sure whether to use @conn or @socket

2 Likes

Thanks for your reply!

I already have the helpers in a shared view module, it’s not specific to liveview, so I’d rather have them in their own place like they’re right now. That ultimately relates to a file structure preference. I’m introducing liveview to an existing project and not every part of it is suitable for liveview, so I don’t want to “give it preference”, so to speak.

The issue with MyApp.Endpoint is that can’t read assigns from it. I was trying to illustrate cases where you need to read data that is common to both structures, but you don’t know which one is available in the template. assigns[:conn] || assigns[:socket] is an option but looks like a dirty hack.
Though you made me realize I could just refactor everything to receive assigns instead and call it a day.

While refactoring you might consider looking at the Github issues related to liveview.