Illustration de Some LiveView in Phoenix views and templates

Some LiveView in Phoenix views and templates

Par Mathieu, Lead Developer

Publié le

How to gradually introduce LiveView functionality into an existing Phoenix regular template web application using the live_render function.

#elixir#phoenix#liveview#featured

The Phoenix framework offers two ways of writing a web application, the first being oriented towards building a classic application with the usual controller/view/templates architecture, and the second way, LiveView, oriented around websockets and enabling the construction of a dynamic application that doesn’t require the browser to reload the entire page.

Choosing one or the other is easy when creating a new page (thanks to the generators), but sometimes we want to add dynamic functionality to an existing page without having to convert everything to LiveView.

Fortunately, the framework offers a live_render/3 function for rendering LiveView components in a template.

Advantages of a hybrid approach

Using the live_render/3 function in a classic template can bring several benefits, including:

  • Enabling gradual adoption: We can introduce LiveView functionality into an existing application, without having to rewrite each page entirely from scratch.
  • Facilitate code reuse: LiveView components created in this way can be reused in different templates, reducing code duplication and improving application consistency.
  • Improved user experience: Thanks to dynamic updates, we can offer a smoother, more responsive user experience, without having to reload the entire page. LiveView offers the advantage of retrieving only the necessary data from the server.
  • Improved developer experience: LiveView enables a more declarative style of programming, where you can define the state and behavior of a component in a single place. This can make your code more readable and easier to reason about.

How to implement this solution

In this example, we’re going to add a simple click counter, inside an regular (non-live) controller/view.

The page is a simple todo list, which we can generate using the command mix phx.gen.html.

View of the example

The controller doesn’t need to be modified and should look like:

# controllers/page_controller.ex
defmodule MyAppWeb.PageController do
  use MyAppWeb, :controller

  def index(conn, _params) do
    render(conn, "index.html")
  end
end

The index action in the MyAppWeb.PageController renders the index.html.heex view. Inside this view, we can use live_render/3 to render our futur MyAppWeb.MyComponent component:

<!-- templates/index.html.heex -->
<%= live_render @conn, MyAppWeb.MyComponent %>

We can now implement the LiveView component itself. This is a very simple component that defines the mount/3 callback as an entry point, a render function containing the HTML template with the button, and a handle_event/3 callback function to react to the button click:

defmodule MyAppWeb.MyComponent do
  use MyAppWeb, :live_view

  def render(assigns) do
    ~H"""
    <.button type="button" phx-click="increment">
      Counter: <%= @counter %>
    </.button>
    """
  end

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

  def handle_event("increment", _value, socket) do
    {:noreply, update(socket, :counter, &(&1 + 1))}
  end
end

There is one problem, however.

If we launch the application with these changes and navigate to the todo list, we notice that the layout is rendered twice.

View of the layout issue

To fix this issue, we can add in the base module of the Phoenix web application (myapp_web.ex in our case), a new function which will allow to define an empty layout:

# myapp_web.ex
def live_render_view do
    quote do
      use Phoenix.LiveView,
        layout: {MyAppWeb.LayoutView, "live_render.html"},
				container: {:div, style: "display: inline-block;"}

      unquote(view_helpers())
    end
  end

Here is the minimum code to include in the layout to display only the component:

<%# components/layouts/live_render.html.heex %>
<%= @inner_content %>

We can now replace in the LiveView componant, the line:

use MyAppWeb, :live_view

Whith this line:

use MyAppWeb, :live_render_view

Additional considerations

The live_render/3 function in Phoenix accepts a third parameter, which is a keyword list of options that can be used to customize the behavior of the component. You can learn more in the Phoenix LiveView documentation.

Conslusion

live_render/3 is a powerful tool that enables developers to gradually introduce LiveView functionality into an existing Phoenix application without having to rewrite each page entirely from scratch. This approach offers several advantages, including code reuse, improved user experience, and improved developer experience. By following the steps outlined in this article, you can easily add dynamic functionality to an existing page without the need to convert everything to LiveView.

I hope you enjoy the post. Thanks for reading, and see you next time!

En parlant de #elixir...