Skip to content

Phoenix LiveView

Example of a Phoenix LiveView app using Electric.

Syncing into Phoenix LiveView using Electric

This is an example app using our Electric.Phoenix integration library.

It uses Electric for read-path sync into a LiveView using electric_stream/4 and standard Phoenix APIs for writes. This keeps the LiveView automatically in-sync with Postgres, without having to re-run queries or trigger any change handling yourself.

See e.g.: lib/electric_phoenix_example_web/live/todo_live/index.ex:

elixir
defmodule Electric.PhoenixExampleWeb.TodoLive.Index do
  use Electric.PhoenixExampleWeb, :live_view

  alias Electric.PhoenixExample.Todos
  alias Electric.PhoenixExample.Todos.Todo

  @impl true
  def mount(_params, _session, socket) do
    {:ok,
     socket
     |> assign(:electric_live, false)
     |> assign(:animate_insert, false)
     |> Electric.Phoenix.LiveView.electric_stream(:todos, Todos.Todo)}
  end

  @impl true
  def handle_params(_params, _url, socket) do
    {:noreply, assign(socket, :todo, %Todo{})}
  end

  @impl true
  # Progress events from the electric client.
  # - `:loaded` is sent when the initial fetch has completed
  # - `:live` is sent when the client is in `live` mode and waiting for the
  #         latest updates from the server
  def handle_info({:electric, {:todos, :loaded}}, socket) do
    {:noreply, socket}
  end

  # here we use the `:live` state to turn on animations for new Todos
  def handle_info({:electric, {:todos, :live}}, socket) do
    {:noreply, socket |> assign(:electric_live, true) |> assign(:animate_insert, true)}
  end

  # Forward all events from the Electric sync stream to the component.
  # This is **required** for the integration.
  def handle_info({:electric, event}, socket) do
    {:noreply, Electric.Phoenix.LiveView.electric_stream_update(socket, event, at: 0)}
  end

  @impl true
  def handle_event("delete", %{"id" => id}, socket) do
    {:ok, _todo} =
      id
      |> Todos.get_todo!()
      |> Todos.delete_todo()

    # Deleting is enough -- Electric will stream the update directly from the
    # database into the views
    {:noreply, socket}
  end

  def handle_event("toggle-completed", %{"id" => id}, socket) do
    {:ok, _todo} =
      id
      |> Todos.get_todo!()
      |> Todos.toggle_complete()

    # Updating is enough -- Electric will stream the update directly from the
    # database into the views
    {:noreply, socket}
  end
end