Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Streams of Nested LV with hooks throws exception #3530

Open
oohnoitz opened this issue Nov 26, 2024 · 0 comments
Open

Streams of Nested LV with hooks throws exception #3530

oohnoitz opened this issue Nov 26, 2024 · 0 comments
Labels
Milestone

Comments

@oohnoitz
Copy link

Environment

  • Elixir version (elixir -v): 1.17.3
  • Phoenix version (mix deps): 1.7.14
  • Phoenix LiveView version (mix deps): 1.0.0-rc7
  • Operating system: Linux
  • Browsers you attempted to reproduce this bug on (the more the merrier): FireFox, Chrome
  • Does the problem persist after removing "assets/node_modules" and trying again? Yes/no: Yes

Actual behavior

This may be a niche usage since it is considered resource intensive. However, the following error is thrown when using patch modify a stream that renders nested LVs. This has previously worked on v1.0.0-rc5 and seems related to the new createHook support for CustomElement: e86c1b1

Uncaught (in promise) TypeError: hook is undefined
    addHook http://localhost:5001/assets/phoenix_live_view/phoenix_live_view.js:3912
    maybeAddNewHook http://localhost:5001/assets/phoenix_live_view/phoenix_live_view.js:3703
    performPatch http://localhost:5001/assets/phoenix_live_view/phoenix_live_view.js:3718
    trackAfter http://localhost:5001/assets/phoenix_live_view/phoenix_live_view.js:2027
    trackAfter http://localhost:5001/assets/phoenix_live_view/phoenix_live_view.js:2027
    perform http://localhost:5001/assets/phoenix_live_view/phoenix_live_view.js:2273
    perform http://localhost:5001/assets/phoenix_live_view/phoenix_live_view.js:2273
    performPatch http://localhost:5001/assets/phoenix_live_view/phoenix_live_view.js:3747
    update http://localhost:5001/assets/phoenix_live_view/phoenix_live_view.js:3880
    time http://localhost:5001/assets/phoenix_live_view/phoenix_live_view.js:4858
    update http://localhost:5001/assets/phoenix_live_view/phoenix_live_view.js:3877
    applyPendingUpdates http://localhost:5001/assets/phoenix_live_view/phoenix_live_view.js:3940
    applyPendingUpdates http://localhost:5001/assets/phoenix_live_view/phoenix_live_view.js:3940
    pushLinkPatch http://localhost:5001/assets/phoenix_live_view/phoenix_live_view.js:4635
    after http://localhost:5001/assets/phoenix_live_view/phoenix_live_view.js:5522
    requestDOMUpdate http://localhost:5001/assets/phoenix_live_view/phoenix_live_view.js:4875
    pushLinkPatch http://localhost:5001/assets/phoenix_live_view/phoenix_live_view.js:4628
    promise callback*pushLinkPatch http://localhost:5001/assets/phoenix_live_view/phoenix_live_view.js:4626
    pushHistoryPatch http://localhost:5001/assets/phoenix_live_view/phoenix_live_view.js:5335
    withPageLoading http://localhost:5001/assets/phoenix_live_view/phoenix_live_view.js:5328
    pushHistoryPatch http://localhost:5001/assets/phoenix_live_view/phoenix_live_view.js:5334
    bindNav http://localhost:5001/assets/phoenix_live_view/phoenix_live_view.js:5299
    after http://localhost:5001/assets/phoenix_live_view/phoenix_live_view.js:5522
    requestDOMUpdate http://localhost:5001/assets/phoenix_live_view/phoenix_live_view.js:4875
    bindNav http://localhost:5001/assets/phoenix_live_view/phoenix_live_view.js:5297
    bindNav http://localhost:5001/assets/phoenix_live_view/phoenix_live_view.js:5284
    bindTopLevelEvents http://localhost:5001/assets/phoenix_live_view/phoenix_live_view.js:5094
    doConnect http://localhost:5001/assets/phoenix_live_view/phoenix_live_view.js:4803
    connect http://localhost:5001/assets/phoenix_live_view/phoenix_live_view.js:4815
    connect http://localhost:5001/assets/phoenix_live_view/phoenix_live_view.js:4815
    <anonymous> http://localhost:5001/?q=a:12
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([
  {:plug_cowboy, "~> 2.5"},
  {:jason, "~> 1.0"},
  {:phoenix, "~> 1.7"},
  # please test your issue using the latest version of LV from GitHub!
  {:phoenix_live_view, github: "phoenixframework/phoenix_live_view", branch: "main", override: true},
])

# build the LiveView JavaScript assets (this needs mix and npm available in your path!)
path = Phoenix.LiveView.__info__(:compile)[:source] |> Path.dirname() |> Path.join("../")
System.cmd("mix", ["deps.get"], cd: path, into: IO.binstream())
System.cmd("npm", ["install"], cd: Path.join(path, "./assets"), into: IO.binstream())
System.cmd("mix", ["assets.build"], cd: path, into: IO.binstream())

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

defmodule Example.NestedLive do
  use Phoenix.LiveView

  def mount(_params, session, socket) do
    {:ok, assign(socket, :item_id, session["item_id"])}
  end
  
  def render(assigns) do
   ~H"""
    <div id={"item-outer-#{@item_id}"}>
      test hook with nested liveview
      <div id={"test-hook-#{@item_id}"} phx-hook="test"></div>
    </div>
    """ 
  end
end

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

  def mount(_params, _session, socket) do
    socket =
      socket
      |> assign(:count, 3)
      |> stream_configure(:items, dom_id: &"item-#{&1.id}")

    {:ok, socket}
  end

  def handle_params(_params, _uri, socket) do
    socket =
    socket
      |> stream(:items, [%{id: 1}, %{id: 2}, %{id: 3}], reset: true)

    {:noreply, socket}
  end

  def render("live.html", assigns) do
    ~H"""
    <script src="/assets/phoenix/phoenix.js"></script>
    <script src="/assets/phoenix_live_view/phoenix_live_view.js"></script>
    <script src="https://cdn.tailwindcss.com"></script>
    <script>
      let liveSocket = new window.LiveView.LiveSocket("/live", window.Phoenix.Socket, {
        hooks: {
         test: {
           mounted() { console.log("aa") }
         }
        }
      })
      liveSocket.connect()
    </script>
    <style>
      * { font-size: 1.1em; }
    </style>
    <%= @inner_content %>
    """
  end

  def render(assigns) do
    ~H"""
    <ul id="stream-list" phx-update="stream">
      <%= for {dom_id, item} <- @streams.items do %>
        <%= live_render(@socket, Example.NestedLive, id: dom_id, session: %{"item_id" => item.id}) %>
      <% end %>
    </ul>
    <.link patch={"/?q=a"}>patch a</.link>
    <.link patch={"/?q=b"}>patch b</.link>
    <div phx-click="inc">+</div>
    """
  end
  
  def handle_event("inc", _params, socket) do
    socket = 
      socket
      |> update(:count, & &1 + 1)
      |> then(&stream_insert(&1, :items, %{id: &1.assigns.count}))

    {: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 Plug.Static, from: {:phoenix, "priv/static"}, at: "/assets/phoenix"
  plug Plug.Static, from: {:phoenix_live_view, "priv/static"}, at: "/assets/phoenix_live_view"

  plug(Example.Router)
end

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

Expected behavior

We should still be able to interact with the page so no exception was thrown during the DOM patching process.

@SteffenDE SteffenDE added the bug label Nov 26, 2024
@SteffenDE SteffenDE added this to the v1.0 milestone Nov 26, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants