Rendering 404s through LiveView

I am currently in the process of converting a Turbolinks style application to LivewView and one issue I run into is how to handle non 2xx responses with LiveView.

Let’s say I have a “live” route containing a parameter /hello/:name and I validate the name in the handle_params callback;

def handle_params(params, _uri, socket) do
    case check_valid_name(params["name"]) do
      {:ok, name} ->
        # Just render the LiveView
        {:noreply, socket}

      {:error, reason} ->
        # Render 404 response as the name is invalid.
    end
  end

I could check the name and return a 404 through the conn instance within a controller that renders the LiveView. But then I don’t have the ability to navigate within the LiveView itself through live_patch.

I can’t find anything about this in the LiveView docs or “official” examples. Any help is really appreciated!

I display a flash message for situations like this and redirect to an index view, e.g. in your {:error, reason} case:

      {:ok, socket
        |> put_flash(:error, msg)
        |> push_redirect(to: Routes.live_path(socket, ReactionWeb.AnalysisProject.Index))
      }

I haven’t figured out how to clear flash messages in my app template without an http round trip, but I’m in a no-mans land between 0.9.0 and 0.10.0 and that was cleared up with the live templates.

This approach may or may not be useful for you, but it works for my use case.

There was a similar discussion in the issues tracker here.

The proposed solution was:

You can have a plug in your router that handles these cases or you can raise an exception on LiveView mount and make the exception be treated as 404 by implementing Plug.Exception.

1 Like

There’s a phx-click="lv:clear-flash" event that you could add to your flash alerts as an interactive way to clear it on click. Or have any other callback that doesn’t do a redirect or patch (these two clear any previously set flash automatically) and doesn’t set a flash, actually clear it.

{:ok, socket
  |> clear_flash()

Yes works like a charm :ok_hand:

To help others finding this threat;

def handle_params(params, _uri, socket) do
  case check_valid_name(params["name"]) do
    {:ok, name} ->
      # Just render the LiveView
      {:noreply, socket}

    {:error, reason} ->
      # Render 404 response as the name is invalid.
      raise ExampleWeb.UserLive.InvalidNameError
  end
end

defmodule ExampleWeb.UserLive.InvalidNameError do
  defexception message: "invalid name", plug_status: 404
end
2 Likes

Thanks @sfusato!

I had seen the clear_flash() but I hadn’t seen the built in "lv:clear-flash" - thanks for the heads up on that. Unfortunately neither will work for me until I port my app layouts to use liveview. I’m a couple of versions behind (0.9.0) - things are moving really quickly right now so I’ll probably wait a couple more weeks until the Phoenix / LiveView settles before rejigging the app templates to work properly.