Phoenix_live_view: phx-click does not reach the function in phx-target. Error: this.getRootById(...) is undefined

Created on 28 May 2020  路  17Comments  路  Source: phoenixframework/phoenix_live_view

Environment

  • Elixir version (elixir -v): 1.10.2
  • Phoenix version (mix deps): 1.5.0
  • Phoenix LiveView version (mix deps): 0.13.2
  • NodeJS version (node -v): 11.13.0
  • NPM version (npm -v): 6.7.0
  • Operating system: Windows 10
  • Browsers you attempted to reproduce this bug on (the more the merrier): Firefox 76.0.1
  • Does the problem persist after removing "assets/node_modules" and trying again? Yes/no: Yes

Actual behavior

I am updating an umbrella application to version 1.5.0 of phoenix and 0.13.2 of liveview and all good to the point of updating dependencies and following the instructions contained in phx-1.5-upgrade.md, but when the user clicks on a button that is assigned a phx-click the browser console throws the error:

TypeError: this.getRootById (...) is undefined
app.js line 119> eval: 918: 23
聽聽聽聽value webpack: /// .../deps/phoenix_live_view/priv/static/phoenix_live_view.js?: 918
聽聽聽聽i webpack: /// .../deps/phoenix_live_view/priv/static/phoenix_live_view.js?: 881
聽聽聽聽G webpack: /// .../deps/phoenix_live_view/priv/static/phoenix_live_view.js?: 434
聽聽聽聽value webpack: /// .../deps/phoenix_live_view/priv/static/phoenix_live_view.js?: 880
聽聽聽聽value webpack: /// .../deps/phoenix_live_view/priv/static/phoenix_live_view.js?: 900
聽聽聽聽forEach self-hosted: 225
聽聽聽聽value webpack: /// .../deps/phoenix_live_view/priv/static/phoenix_live_view.js?: 899
聽聽聽聽value webpack: /// .../deps/phoenix_live_view/priv/static/phoenix_live_view.js?: 912
聽聽聽聽value webpack: /// .../deps/phoenix_live_view/priv/static/phoenix_live_view.js?: 1079
聽聽聽聽debounce webpack: /// .../deps/phoenix_live_view/priv/static/phoenix_live_view.js?: 1362
聽聽聽聽value webpack: /// .../deps/phoenix_live_view/priv/static/phoenix_live_view.js?: 1222
聽聽聽聽value webpack: /// .../deps/phoenix_live_view/priv/static/phoenix_live_view.js?: 1078

Apparently the file \apps\myapp_web\priv\static\js\ app.j
is not being updated with liveview version change.

Expected behavior

If the user click button connected "phx-click", "handle_event" method execute.

list_component.ex

```
defmodule TestSystemWeb.ListComponent do
use Phoenix.LiveComponent
use Phoenix.HTML
alias TestSystem.{
StructureHandler
}

def mount(socket) do
{:ok, assign(socket,
list_configuration: StructureHandler.list_structures()
)}
end

def update(attrs, socket) do
{:ok, assign(socket, id: attrs.id)}
end

def handle_event("open_structure", params, socket) do
assign(socket, structure: params["id"])
id =
params
|> Map.get("id")

{:noreply, assign(socket, new?: false, edit?: true, structure_id: id)}

end

end

def render(assigns) do
~L"""

<div id="structure_list" class="bg-white h-hoch-93 w-80 mt-16 ml-16 block float-left">
  <div class="w-full py-2 bg-blue-700">
    <p class="ml-2 font-bold text-lg text-white">Configuraci贸n</p>
  </div>

<div class="h-hoch-75 overflow-y-scroll pb-16 mt-2">
  <%= for item <- @list_configuration do %>
    <div class="w-full px-2 block">
      <button phx-click="open_structure" phx-value-id="<%= item.id %>" phx-target="#structure_list" class="border cursor-pointer w-full block bg-gray-200 p-3 mt-2 rounded relative hover:bg-gray-300">
        <h2 class="text-gray-700 text-xl">Nivel: <%= item.level %></h2>
        <label class="inline-block cursor-pointer text-gray-600 font-bold text-sm">Tama帽o: <b><%= item.size %></b></label>
        <label class="ml-10 inline-block cursor-pointer text-gray-600 font-bold text-sm">M谩ximo actual: <b><%= item.max_current_size %></b></label>
      </button>
    </div>

  <% end %>
</div>
</div>
"""

end
end

needs more info

Most helpful comment

It seems the use of UUID.uuid4() (or any other random id generator) as an id for a nested liveview is causing the error. This will result in one ID on http render and a totally different id on subsequent socket render.

All 17 comments

Can you please provide a sample application that reproduces the error? If the JS file is not being updated, then it is not a LV issue and something else is at play.

Elixir version (elixir -v): 1.10.0
Phoenix version (mix deps): 1.5.3
Phoenix LiveView version (mix deps): 0.13.2
NodeJS version (node -v): v10.15.2
NPM version (npm -v): 6.14.4
Firefox: 76.0.1

I encountered this exact problem in my application too. It doesn't occur consistently though. When loading a page with a live view in it sometimes the nprogress spinner spins for a very long time (20+ seconds) and clicking on a button with a phx-click property while the page is loading always leads to the TypeError: this.getRootById (...) is undefined exception that @pedrogmucino posted. However, when the page loads fine the buttons behave correctly.

I managed to reproduce the "spinner spins for a very long time" problem on a fresh LiveView app:

mix archive
* hex-0.20.5
* phx_new-1.5.3

mix phx.new --live foo
  Fetch and install dependencies? [Yn] Y

cd foo

mix ecto.create

iex -S mix phx.server

Then go to localhost:4000 and simply reload the page many times until you hit the problem (i.e. the page takes 20+ seconds to load):
Screenshot 2020-06-01 at 13 30 08

You can see the loading issue in this video too, the problem occurs after 00:20.

@pedrogmucino tried running your application, but I get a a compilation error:

== Compilation error in file lib/helsinki/common/schema_formatter.ex ==
** (CompileError) lib/helsinki/common/schema_formatter.ex:11: AccountingSystem.AccountCodeSchema.__struct__/1 is undefined, cannot expand struct AccountingSystem.AccountCodeSchema.

@jordi-chacon The page becomes LiveView interactive once nprogress is done loading.

window.addEventListener("phx:page-loading-stop", info => NProgress.done())

I assume interactivity is not to be expected until the websocket connection is established and LiveView is fully wired.

I assume interactivity is not to be expected until the websocket connection is established and LiveView is fully wired.

@sfusato Fair enough. However, is it expected for LiveView to take 20+ seconds to be fully wired on a brand-new unaltered application created with mix phx.new --live foo?

@pedrogmucino can you provide a more minimal application with fewer files and no DB, if possible? It's much easier for us to verify an issue with a pruned down that requires less setup and audit. Thanks!

@chrismccord should I open a separate issue for the problem I described in my two previous comments? I believe the error experienced by @pedrogmucino is caused by the problem I'm describing though, but I can certainly open a separate issue if you prefer that.

Appreciate the stellar work on Phoenix.LiveView @chrismccord and team. Appreciate all the work so far 馃帀 馃殌 馃挴 馃帄

I also hit a TypeError: this.getRootById(...) is undefined error, though in my case it's only thrown when rendering a nested live_render.

    Elixir version (elixir -v): 1.8.2
    Phoenix version (mix deps): 1.5.3 
    Phoenix LiveView version (mix deps): 0.13.2
    NodeJS version (node -v): 10.16.3
    NPM version (npm -v): 6.9.0
    Operating system: OS X 10.15.4
    Browsers you attempted to reproduce this bug on (the more the merrier): Firefox 72.0.2
    Does the problem persist after removing "assets/node_modules" and trying again? Yes/no: Yes

Firefox debugger points to:

// ...
{
  key: "destroyViewByEl",
  value: function (e) {
    this.getRootById(e.getAttribute("data-phx-root-id")).destroyDescendent(e.id);
  }
}
// ...

The parent live view is being rendered using Phoenix.LiveView.Router.live/4. The child live view is being called using Phoenix.LiveView.Helpers.live_render/3. The child live view is being passed a unique id value and the data-phx-parent-id attribute is set in the child live view container element.

Let me know what additional information I can provide. And like Jordi Chacon mentioned, if I should open a separate issue rather than appending to this one. Thanks!

A minimal example application that reproduces the issue would be extremely helpful. Thanks!

Sure thing @chrismccord! Here's a minimal repository to reproduce:

https://github.com/chrislaskey/phx-demo-liveview-debug

I broke down the scenarios I found that do and do not cause the error:

Screen Shot 2020-06-04 at 10 57 07 AM

Example of the Error

Screen Shot 2020-06-04 at 10 49 09 AM

Full details:

    Elixir version (elixir -v): 1.8.2
    Phoenix version (mix deps): 1.5.3 
    Phoenix LiveView version (mix deps): 0.13.2
    NodeJS version (node -v): 10.16.3
    NPM version (npm -v): 6.9.0
    Operating system: OS X 10.15.4
    Browsers you attempted to reproduce this bug on (the more the merrier): Firefox 72.0.2
    Does the problem persist after removing "assets/node_modules" and trying again? Yes/no: Yes

It seems the use of UUID.uuid4() (or any other random id generator) as an id for a nested liveview is causing the error. This will result in one ID on http render and a totally different id on subsequent socket render.

Good find @sfusato! It seems we are trying to render something with the same ID and then it suddenly changes. Although I would say LV should probably handle those cases cleanly. It may be expected for an ID to change.

Thank you @sfusato! Your explanation makes a lot of sense. I confirmed within the test application this can be easily fixed by either:

  • Setting the child live view id to a static value
  • Defining the child live view id in within the parent live view

Appreciate the time from the team to help identify the core problem in my approach 馃帀 馃憤

Not sure this is useful, but on my app I don't have any child liveviews and I still observe this bug from time to time. (I've never been able to observe it myself, but Sentry catches a couple of those everyday).
Perhaps another way to solve this could be to wrap the liveSocket.connect() call in a try catch block and and display an error for the user to reload the page?
(just a thought)

I wonder if this can also be caused by a race condition. You click something right at the time its target has been removed from the page.

@happysalada your issue was fixed on 909e83b. I am leaving this open because I still think LiveView should be able to copy with the IDs changing on rendering.

Well, the fix for @happysalada also fixed the issue for @chrislaskey with random IDs, so we are all good here!

Was this page helpful?
0 / 5 - 0 ratings

Related issues

tfwright picture tfwright  路  3Comments

jamilabreu picture jamilabreu  路  5Comments

StormBytePP picture StormBytePP  路  4Comments

josevalim picture josevalim  路  3Comments

chrismccord picture chrismccord  路  4Comments