Phoenix_live_view: Documentation for converting an app to LiveView missing a step

Created on 9 May 2020  路  6Comments  路  Source: phoenixframework/phoenix_live_view

I was following this guide:

https://hexdocs.pm/phoenix_live_view/installation.html

To add LiveView support to an existing Phoenix app. I found I was getting a compilation error:

== Compilation error in file lib/app_web/live/example_live/show.ex ==
** (UndefinedFunctionError) function AppWeb.live_view/0 is undefined or private
    AppWeb.live_view()
    expanding macro: AppWeb.__using__/1
    lib/app_web/live/example_live/show.ex:2: AppWeb.ExampleLive.Show (module)
    (elixir) expanding macro: Kernel.use/2
    lib/app_web/live/example_live/show.ex:2: AppWeb.ExampleLive.Show (module)
    (elixir) lib/kernel/parallel_compiler.ex:229: anonymous fn/4 in Kernel.ParallelCompiler.spawn_workers/7

Looking at the generated template file here:

https://github.com/phoenixframework/phoenix/blob/f7784f86ed803a39eb45486f0e031e974e708818/installer/templates/phx_single/lib/app_name_web.ex

It looks like the instructions to add some lines to lib/my_app_web.ex are incomplete - I also needed to add the live_view and live_component functions. I also found I needed to add:

      import Phoenix.LiveView.Helpers
      import CloeWeb.LiveHelpers

into live_view/0. (not sure if that is correct as I'm new to Phoenix but it fixed the next errors I got).

Most helpful comment

Thanks @josevalim! I looked at your docs changes and applied what you suggested to my site. There seemed to be one more line I needed. With your code in lib/cloe_web.ex I was getting:

Erlang/OTP 22 [erts-10.5] [source] [64-bit] [smp:8:8] [ds:8:8:10] [async-threads:1] [hipe]

Compiling 20 files (.ex)

== Compilation error in file lib/cloe_web/live/room_live/show.ex ==
** (CompileError) lib/cloe_web/live/room_live/show.html.leex:4: undefined function live_modal/3
    (elixir) src/elixir_locals.erl:98: :elixir_locals."-ensure_no_undefined_local/3-lc$^0/1-0-"/2
    (elixir) src/elixir_locals.erl:99: anonymous fn/3 in :elixir_locals.ensure_no_undefined_local/3
    (stdlib) erl_eval.erl:680: :erl_eval.do_apply/6
    (elixir) lib/kernel/parallel_compiler.ex:229: anonymous fn/4 in Kernel.ParallelCompiler.spawn_workers/7

I added import CloeWeb.LiveHelpers to 'view_helpers' in lib/cloe_web.ex and that fixed it.

Thank you for your help, I'm really enjoying learning Phoenix and LiveView, so thank you for all your work on it!

All 6 comments

Looks like you typo'd a step. Did you include use AppWeb.Example.live_view by accident instead of use AppWeb, :live_view ? Failing that, can you share your show.ex module? Thanks!

_Note: I replaced Cloe => App and Room => Example in my issue report above. I've gone back to the real app names below to avoid confusion._

Nope, show.ex had use CloeWeb, :live_view in it as the first line - that was part of the generated code, I didn't write it.

I should mention that I ran:

mix phx.gen.live Rooms Room rooms --no-context --no-schema

Because I was trying to add a new LiveView route to an existing context.

Here's the full show.ex:

defmodule CloeWeb.RoomLive.Show do
  use CloeWeb, :live_view

  alias Cloe.Rooms

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

  @impl true
  def handle_params(%{"id" => id}, _, socket) do
    {:noreply,
     socket
     |> assign(:page_title, page_title(socket.assigns.live_action))
     |> assign(:room, Rooms.get_room!(id))}
  end

  defp page_title(:show), do: "Show Room"
  defp page_title(:edit), do: "Edit Room"
end

and the original error (without edits):

Erlang/OTP 22 [erts-10.5] [source] [64-bit] [smp:8:8] [ds:8:8:10] [async-threads:1] [hipe]

Compiling 23 files (.ex)

== Compilation error in file lib/cloe_web/live/room_live/show.ex ==
** (UndefinedFunctionError) function CloeWeb.room_view/0 is undefined or private
    CloeWeb.room_view()
    expanding macro: CloeWeb.__using__/1
    lib/cloe_web/live/room_live/show.ex:2: CloeWeb.RoomLive.Show (module)
    (elixir) expanding macro: Kernel.use/2
    lib/cloe_web/live/room_live/show.ex:2: CloeWeb.RoomLive.Show (module)
    (elixir) lib/kernel/parallel_compiler.ex:229: anonymous fn/4 in Kernel.ParallelCompiler.spawn_workers/7

Can you include your entire project, or at least your app_web.ex? The 2nd stacktrace you posted is different than the first. This one is showing CloeWeb.room_view/0 is undefined or private CloeWeb.room_view() where the other one was live_view/0 is undefined. You indeed need to add the live_view/0 clause to your app_web.ex, and the generator should have output:
https://github.com/phoenixframework/phoenix/blob/master/lib/mix/tasks/phx.gen.live.ex#L181-L183

Sorry, I was trying a bunch of things to fix it and looks like I pulled the wrong error out of my console history. The error was definitely about live_view/0.

That output from the generator is the hint I was missing, but I saved the output from running mix phx.gen.live and it doesn't look like it showed for me for some reason (could it be because I ran with --no-context --no-schema?). This was the output I got:

* creating lib/cloe_web/live/room_live/show.ex
* creating lib/cloe_web/live/room_live/index.ex
* creating lib/cloe_web/live/room_live/form_component.ex
* creating lib/cloe_web/live/room_live/form_component.html.leex
* creating lib/cloe_web/live/room_live/index.html.leex
* creating lib/cloe_web/live/room_live/show.html.leex
* creating test/cloe_web/live/room_live_test.exs
* creating lib/cloe_web/live/modal_component.ex
* creating lib/cloe_web/live/live_helpers.ex
* injecting lib/cloe_web.ex

Add the live routes to your browser scope in lib/cloe_web/router.ex:

    live "/rooms", RoomLive.Index, :index
    live "/rooms/new", RoomLive.Index, :new
    live "/rooms/:id/edit", RoomLive.Index, :edit

    live "/rooms/:id", RoomLive.Show, :show
    live "/rooms/:id/show/edit", RoomLive.Show, :edit

Here is my current cloe_web.ex. I added the import lines suggested in the docs here manually, after which point I got the error. I then added the functions live_view and live_component from here myself to fix the problem. At that point I got this error:

Erlang/OTP 22 [erts-10.5] [source] [64-bit] [smp:8:8] [ds:8:8:10] [async-threads:1] [hipe]

Compiling 22 files (.ex)

== Compilation error in file lib/cloe_web/live/room_live/show.ex ==
** (CompileError) lib/cloe_web/live/room_live/show.html.leex:4: undefined function live_modal/3
    (elixir) src/elixir_locals.erl:98: :elixir_locals."-ensure_no_undefined_local/3-lc$^0/1-0-"/2
    (elixir) src/elixir_locals.erl:99: anonymous fn/3 in :elixir_locals.ensure_no_undefined_local/3
    (stdlib) erl_eval.erl:680: :erl_eval.do_apply/6
    (elixir) lib/kernel/parallel_compiler.ex:229: anonymous fn/4 in Kernel.ParallelCompiler.spawn_workers/7

so I also added the two import lines within live_view to get what I have now:

defmodule CloeWeb do
  @moduledoc """
  The entrypoint for defining your web interface, such
  as controllers, views, channels and so on.

  This can be used in your application as:

      use CloeWeb, :controller
      use CloeWeb, :view

  The definitions below will be executed for every view,
  controller, etc, so keep them short and clean, focused
  on imports, uses and aliases.

  Do NOT define functions inside the quoted expressions
  below. Instead, define any helper function in modules
  and import those modules here.
  """

  def controller do
    quote do
      use Phoenix.Controller, namespace: CloeWeb

      import Plug.Conn
      import CloeWeb.Gettext
      import Phoenix.LiveView.Controller
      alias CloeWeb.Router.Helpers, as: Routes
    end
  end

  def view do
    quote do
      use Phoenix.View,
        root: "lib/cloe_web/templates",
        namespace: CloeWeb

      # Import convenience functions from controllers
      import Phoenix.Controller, only: [get_flash: 1, get_flash: 2, view_module: 1]
      import Phoenix.LiveView.Helpers
      import CloeWeb.LiveHelpers

      # Include shared imports and aliases for views
      unquote(view_helpers())
    end
  end

  def live_view do
    quote do
      use Phoenix.LiveView,
        layout: {CloeWeb.LayoutView, "live.html"}

      import Phoenix.LiveView.Helpers
      import CloeWeb.LiveHelpers

      unquote(view_helpers())
    end
  end

  def live_component do
    quote do
      use Phoenix.LiveComponent

      unquote(view_helpers())
    end
  end

  def router do
    quote do
      use Phoenix.Router

      import Plug.Conn
      import Phoenix.Controller
      import Phoenix.LiveView.Router
    end
  end

  def channel do
    quote do
      use Phoenix.Channel
      import CloeWeb.Gettext
    end
  end

  defp view_helpers do
    quote do
      # Use all HTML functionality (forms, tags, etc)
      use Phoenix.HTML

      # Import basic rendering functionality (render, render_layout, etc)
      import Phoenix.View

      import CloeWeb.ErrorHelpers
      import CloeWeb.Gettext
      alias CloeWeb.Router.Helpers, as: Routes
    end
  end

  @doc """
  When used, dispatch to the appropriate controller/view/etc.
  """
  defmacro __using__(which) when is_atom(which) do
    apply(__MODULE__, which, [])
  end
end

The issue is that the LiveView installation is just enough to install LiveView, but it is not enough to use the phx.gen.live generators. I will add the missing steps, thanks for reporting.

Thanks @josevalim! I looked at your docs changes and applied what you suggested to my site. There seemed to be one more line I needed. With your code in lib/cloe_web.ex I was getting:

Erlang/OTP 22 [erts-10.5] [source] [64-bit] [smp:8:8] [ds:8:8:10] [async-threads:1] [hipe]

Compiling 20 files (.ex)

== Compilation error in file lib/cloe_web/live/room_live/show.ex ==
** (CompileError) lib/cloe_web/live/room_live/show.html.leex:4: undefined function live_modal/3
    (elixir) src/elixir_locals.erl:98: :elixir_locals."-ensure_no_undefined_local/3-lc$^0/1-0-"/2
    (elixir) src/elixir_locals.erl:99: anonymous fn/3 in :elixir_locals.ensure_no_undefined_local/3
    (stdlib) erl_eval.erl:680: :erl_eval.do_apply/6
    (elixir) lib/kernel/parallel_compiler.ex:229: anonymous fn/4 in Kernel.ParallelCompiler.spawn_workers/7

I added import CloeWeb.LiveHelpers to 'view_helpers' in lib/cloe_web.ex and that fixed it.

Thank you for your help, I'm really enjoying learning Phoenix and LiveView, so thank you for all your work on it!

Was this page helpful?
0 / 5 - 0 ratings

Related issues

josevalim picture josevalim  路  3Comments

lukaszsamson picture lukaszsamson  路  5Comments

lukegalea picture lukegalea  路  3Comments

LightningK0ala picture LightningK0ala  路  5Comments

tfwright picture tfwright  路  3Comments