Eiji

Eiji

Phoenix.LiveView.JS does not respect transition time option and calls `JS.push/1` immediately

Hi, here is an example script:

Application.put_env(:sample, Example.Endpoint,
  http: [ip: {127, 0, 0, 1}, port: 5001],
  server: true,
  live_view: [signing_salt: "aaaaaaaa"],
  secret_key_base: String.duplicate("a", 64)
)

Mix.install(
  jason: "~> 1.0",
  phoenix: "~> 1.7.0",
  phoenix_live_view: "~> 0.20.0",
  plug_cowboy: "~> 2.5"
)

defmodule Example.ErrorView do
  def render(template, _), do: Phoenix.Controller.status_message_from_template(template)
end

defmodule Example.HomeLive do
  use Phoenix.LiveView, layout: {__MODULE__, :live}

  alias Phoenix.LiveView.JS

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

  defp phx_vsn, do: Application.spec(:phoenix, :vsn)
  defp lv_vsn, do: Application.spec(:phoenix_live_view, :vsn)

  def render("live.html", assigns) do
    ~H"""
    <script src={"https://cdn.jsdelivr.net/npm/phoenix@#{phx_vsn()}/priv/static/phoenix.min.js"}></script>
    <script src={"https://cdn.jsdelivr.net/npm/phoenix_live_view@#{lv_vsn()}/priv/static/phoenix_live_view.min.js"}></script>
    <script>
      let liveSocket = new window.LiveView.LiveSocket("/live", window.Phoenix.Socket)
      liveSocket.connect()
    </script>
    <style>
    </style>
    <%= @inner_content %>
    """
  end

  def render(assigns) do
    ~H"""
    <button class="fadeIn" phx-click={
      JS.toggle_class("fadeIn fadeOut", time: 5000)
      |> JS.push("example")
    }>Example</button>
    """
  end

  def handle_event("example", _params, socket) do
    IO.inspect(Time.utc_now())
    {:noreply, socket}
  end
end

defmodule Example.Router do
  use Phoenix.Router
  import Phoenix.LiveView.Router

  pipeline :browser do
    plug(:accepts, ["html"])
  end

  scope "/", Example do
    pipe_through(:browser)

    live("/", HomeLive, :index)
  end
end

defmodule Example.Endpoint do
  use Phoenix.Endpoint, otp_app: :sample
  socket("/live", Phoenix.LiveView.Socket)
  plug(Example.Router)
end

{:ok, _} = Supervisor.start_link([Example.Endpoint], strategy: :one_for_one)
Process.sleep(:infinity)

The problem is that JS.push/1 is called immediately without giving a chance for animation. Using this example you can reproduce the issue (see inspected time in logs).

I have no idea if it’s a bug or intended behaviour. All I know is that at the start of every handle_event/3 function body For now instead of inspecting time I’m adding: Process.sleep/1 call which looks like a workaround, but after adding it animation works as expected. I wonder if other people experienced the same and if so what did you do with that. Is Process.sleep/1 call good here or maybe you can recommend some alternative (within JS + handle_event/3).

Most Liked

chrismccord

chrismccord

Creator of Phoenix

This is as designed. You want the interaction to happen as soon as possible, and the UI feedback from the animation can mask the latency. What the :time does is locks the UI from patching over the animation for that duration, so you don’t end up stomping on your animations. You definitely don’t want to sleep in your handlers. The animation time should almost always be 200-300ms and not much more. If you are trying to lock the UI for long periods because you are doing some heavily async work, consider using <.async_result> and handling loading states, but it’s not clear what your real app goals are so hard to say.

Lucassifoni

Lucassifoni

For that kind of feature I would make the button transitionable after the first render, and its visibility would depend on UI state.

Change the state to reflect the fact work has started (and this hides the button), and when you hear back from the background work, change the state to reflect that work is done.

If you see the UI as the result of a pure function over a state, a bit like Elm does it, it’s way easier than juggling with timings. Of course we also have JS to do small bits of this client-side for optimistic updates, but this shouldn’t cover “how long does work run for”.

Process.sleep will freeze this specific liveview process for the connected user for the duration of the sleep and is to be avoided.

Where Next?

Popular in Questions Top

beno
I will often find my self writing things similar to: case some_value do nil -&gt; something() "" -&gt; something() _ -&gt; somethi...
New
lastday4you
I wanted to check elixir version in phoenix because i found that my elixir is 1.5 but when i use Enum.chunk_by it said the function is un...
New
qwerescape
Is there a way to get the call stack or stack trace at any point in the code? Not from exceptions, but an expression that returns how the...
New
electic
Hi, I am new to Elixir. I am trying to use the DateTime component to insert a date into MySQL however the there seems to be no way to fo...
New
tduccuong
Hi, is there any work on GUI with Elixir, that is similar to Electron/Javascript? My idea is to bundle Phoenix and BEAM into a single se...
New
fireproofsocks
I’m working on defining a simple Ecto schema for a table (in PostGres), but I don’t see where I can define a column as NOT NULL. Conside...
New
stefanluptak
Hello everybody, usually, I use a 29" ultra-wide monitor for VSCode which can easily accomodate explorer (files panel) + file with code ...
New
jerry
Good day to you all. I have been struggling to get a query involving like and ilike to work. Can anyone assist me on this, please? pro...
New
vrod
I am using the Starship cross-shell prompt – it seems pretty nice, but I get some errors: [WARN] - (starship::utils): Executing command ...
New
Brian
What is the proper way to load a module from a file in to IEX? In the python world, doing something like this pretty standard: from ....
New

Other popular topics Top

axelson
This post is a wiki (feel free to hit the edit button near the bottom right of this post to add your own changes!) This post collects co...
239 48342 226
New
electic
Hi, I am new to Elixir. I am trying to use the DateTime component to insert a date into MySQL however the there seems to be no way to fo...
New
msaraiva
Surface is an experimental library built on top of Phoenix LiveView and its new LiveComponent API that aims to provide a more declarative...
564 43757 214
New
belgoros
I’m not a pro in using Regex and can’t figure out why the following behaviour happens, especially if we take into account the difference ...
New
freewebwithme
Using vs code and installed ElixirLS: support and debugger. And I got an error popped up on start up says Failed to run ‘elixir’ comma...
New
aesmail
Hello guys, I have finally made it. I created an admin interface for a framework. It’s been on my todo list for years and with the curre...
New
romenigld
I am trying to run a deploy with docker and I successfully runned with this command: docker build -t romenigld/blog-prod . but when I t...
New
klo
Got a question about when to concat vs. prepending items to list then reversing to achieve appending. So i know lists boil down to [1 | ...
New
openscript
Hello! Sorry for this astonishing simple question, but I’m really stuck. I try to set up the intellij-elixir plugin, but I don’t know ho...
New
dokuzbir
I want to highlight html closing tags when i click a html tag. That works in .html files but doesnt work for html.eex templates. How can...
New

Latest on Elixir Forum

Elixir Forum

We're in Beta

About us Mission Statement