Athunnea

Athunnea

What happens: User opens LiveView page and clicks a button. LiveView handle_event calls a function that crashes. LiveView restarts. User is unaware that something went wrong

What I expect to happen: user is informed that something went wrong. Classic controllers show the 500 error page in similar case.

Error and exception handling doc says

If the error happens during an event, the LiveView process will crash. The client will notice the error and remount the LiveView - without reloading the page. This is enough to update the page and show the user the latest information.

But nothing on how to track this and notify user. I guess I could wrap each function call in try/rescue block and issue a notification myself, but I hope there is a better way

I’d appreciate an advice

Showing Posts 1 to 10

APB9785

APB9785

Creator of ECSx

Inside handle_event you need to also handle the “bad” result(s) from your function call, usually with a case statement. For example:

def handle_event("some_event", params, socket) do
  case function_with_multiple_results(params) do
    good_result ->
      socket = intended_effects(socket)
      {:noreply, socket}

    bad_result ->
      socket = show_my_error_page(socket)
      {:noreply, socket}
  end
end
cenotaph

cenotaph

Display the error message on the view itself rather than sending them to a new page?

<% if @error do %>
<div class="error">You don't have permissions<div>
</div>
def handle_event("some_event", params, socket) do
  case function_with_multiple_results(params) do
    good_result ->
      socket = intended_effects(socket)
      {:noreply, socket}

    bad_result ->
      socket = assign(socket, error: "my error")
      {:noreply, socket}
  end
end

or

socket |> put_flash(socket, :info, "It worked!")
socket |> put_flash(socket, :error, "You can't access that page")
Athunnea

Athunnea OP

There might be a case when intended_effects() unexpectedly raises – due to a bug for example. In this case LV will just go back to mount. And a user has no idea that something went wrong, other than no changes on the page.

I’d expect LV to know about that. At least it knows if raise happens in mount() and shows the error page.

APB9785

APB9785

Creator of ECSx

In this scenario, the LiveView “goes back to mount” because it crashed and was replaced by a new LiveView, which knows nothing about the old one.

If you’re going to go through the effort of reporting the crash, you might as well just fix the error to not crash the LiveView! Within intended_effects() just like in handle_event you should have all possible cases accounted for (this is the standard in a functional language). If there is an error case, a changeset should be returned containing the errors and these errors displayed in the LV. It should never result in a LV crash.

Are you using Ecto to handle your data? Generally the Ecto callbacks return {:ok, struct} on success, and {:error, changeset} on failure. Then you can wrap them in a case statement like shown earlier:

case Accounts.update_user_password(user, password, user_params) do
  {:ok, _user} ->
    socket = put_flash(socket, :info, "Password updated successfully.")
    {:noreply, socket}

  {:error, changeset} ->
    socket = assign(socket, password_changeset: changeset)
    {:noreply, socket}
end

and display the errors to the user (here the example is for a password reset form)

<%= f = form_for @password_changeset, "#", phx_submit: "change_password" %>

  <%= if @password_changeset.action do %>
    <div class="alert alert-danger">
      <p>Oops, something went wrong! Please check the errors below.</p>
    </div>
  <% end %>

  <%= label f, :password, "New password" %>
  <%= password_input f, :password %>
  <%= error_tag f, :password %>

  <%= label f, :current_password, "Current password" %>
  <%= password_input f, :current_password %>
  <%= error_tag f, :current_password %>

  <%= submit "Change password" %>
</form>
Athunnea

Athunnea OP

I understand that the best approach is to produce bugs free code and expect all possible outcomes from functions. But bugs happen. Things go wrong. Not all things are as simple as Repo.update. There is always a lag between error reported and error fixed during which users face the error.

Seeing 500 page is no good. But even worse is not seeing it when something went wrong because then user has no idea if a function worked or not.

What I don’t understand is that exceptions on mount are caught and converted to an exception page by Phoenix error views - pretty much like the way it works with controllers - quote from LV docs. But exceptions on handle_event are not converted to error view. So if exception happens on mount - the user knows that there is a server error. If exception happens after a button click - the user is unaware, because the page stays the same.

benwilson512

benwilson512

Author of Craft GraphQL APIs in Elixir with Absinthe

This isn’t exactly accurate. In some sense, this is less about mount vs handle_event, and more about the static vs live interactions. Crashes in any of the functions called statically are part of the plug pipeline (mount, handle_params) result in plug handling the error and then you get a 500. Those same functions (and any other functions) when called during the live render crash the process, and then the front end tries to reconnect.

Athunnea

Athunnea OP

It’s about user experience with the LiveView. If raise happens on mount the error page is rendered. If raise happens on handle_event - the error page is not rendered, and user is unaware that something went wrong, LiveView silently restarts without refreshing the page.

I’m looking for a way to let the user know that there was an error. Ideally without having to wrap all calls into try/rescue. So far I was unable to find anything in the docs

derek-zhou

derek-zhou

Both 500 and restarts are bad. In liveview, restart is simpler to implement, and in “deadview” 500 is simpler to implement. So what you are seeing here as discrepancy is the library making the least amount of effort when the developer’s intention is unknown.

Athunnea

Athunnea OP

I agee

I’m not looking for discrepancies. I’m looking for an answer to the question: How to notify a user about exception in the LiveView handle_event? I still hope there is a solution better than wrapping function calls with try/catch.

derek-zhou

derek-zhou

It should be possible to make a safe_handle_event wrapper macro to do that. Someone better than me in meta-programming can step up to take the challenge?

Where Next? Top

Trending in Questions Top

stjefim
Hello! Suppose you are building workflow (order / task / payment) processing system with the following requirements: Each workflow con...
New
jonnycharles
I’m in search of an Elixir library that offers PDF generation capabilities similar to Ruby’s Prawn. While there have been discussions abo...
New
spammy
I’m looking to build a personal workflow to quickly deploy web applications written in elixir/phoenix, for local consumption (ie not on t...
New
dli
Before I dive in myself, did anyone successfully sprinkle Hologram into their existing LiveView app? Looking for hints regarding: Addi...
New
roeland
Kia ora, We have been using elixir-google-api to connect to Google Drive. However, with the updates to Tesla due to CVEs this is now bro...
New
bottlenecked
Hi all, I wanted to ask how the community is dealing with post-release steps. Today we have Ecto migrations, which make sure that the db...
New
rahultumpala
Hello, I have an Elixir backend that implements a custom protocol over TCP. I want to load test the backend and assess the performance o...
New

Other Trending Topics Top

JesseHerrick
Hey, I’m Jesse and I’m the main contributor behind Dexter, a full-featured, lightning-fast Elixir LSP optimized for large codebases. It s...
New
jimsynz
Beam Bots (or just BB for short) is a framework for building fault-tolerant robotics applications in Elixir using familiar OTP patterns. ...
New
mcass19
ExRatatui lets you cook up rich terminal UIs in Elixir, powered by Rust’s ratatui via Rustler NIFs. Build interactive terminal applicatio...
New
Damirados
Hello everyone. After busy few months I am happy to announce v0.1.0 of Emerge &amp; Solve. They are GUI (Emerge) and State management (S...
New
netoum
Corex is an accessible, unstyled UI component library for Phoenix that integrates Zag.js state machines using Vanilla JavaScript and Live...
New
ausimian
Emily is an Elixir library that runs Nx computations on Apple’s MLX. Install it as the default Nx backend and Nx, defn, Axon, Nx.Serving,...
New

We're in Beta

About us Mission Statement

Options

Thread Display Mode




Thread Preview

Skip Thread Previews