phx-hook not working on an element mounted by a LiveComponent #3423
Closed
Description
Environment
- Elixir version (elixir -v): 1.17.2
- Phoenix version (mix deps): 1.17.14
- Phoenix LiveView version (mix deps): 0.18.3, 0.20.17, 1.0.0-rc.6
- Operating system: macOS Sonoma
- Browsers you attempted to reproduce this bug on (the more the merrier): Safari, Chrome
- Does the problem persist after removing "assets/node_modules" and trying again? Yes/no: yes
Code: https://github.com/borisgoro/hooks_test
I created the app with mix phx.new hooks_test
and tried upgrading the live view version to 0.20.12, ..., 1.0.0-rc.6 with the same result.
Define two hooks:
const liveSocket = new LiveSocket('/live', Socket, {
params: { _csrf_token: csrfToken },
hooks: {
Hook1: {
mounted () {
console.log('Hook1 mounted')
}
},
Hook2: {
mounted () {
console.log('Hook2 mounted')
}
}
}
})
and a LiveComponent with a "panel" for each hook:
defmodule HooksTestWeb.TestLiveComponent do
use HooksTestWeb, :live_component
@impl true
def render(%{panel: 1} = assigns) do
~H"""
<div id="panel1" phx-hook="Hook1" class="mt-2 p-2 border-2">
<.panel panel="1" target={@myself} />
</div>
"""
end
def render(%{panel: 2} = assigns) do
~H"""
<div id="panel2" phx-hook="Hook2" class="mt-2 p-2 border-2">
<.panel panel="2" target={@myself} />
</div>
"""
end
def panel(assigns) do
~H"""
<div><%= "Panel #{@panel}" %></div>
<button class="mt-2 p-1 border-2" phx-click="panel1" phx-target={@target}>Panel 1</button>
<button class="mt-2 p-1 border-2" phx-click="panel2" phx-target={@target}>Panel 2</button>
"""
end
@impl true
def handle_event("panel1", _, socket) do
{:noreply, assign(socket, panel: 1)}
end
def handle_event("panel2", _, socket) do
{:noreply, assign(socket, panel: 2)}
end
end
Hook1.mounted() is called on the initial render, but Hook2.mounted() is not called when the Panel 2 button is clicked.
Identical code (without the phx-target stuff) works fine in a LiveView:
defmodule HooksTestWeb.HomeLive do
use Phoenix.LiveView, layout: {HooksTestWeb.Layouts, :app}
@impl true
def mount(_params, _session, socket) do
{:ok, assign(socket, panel: 1)}
end
# @impl true
# def render(assigns) do
# ~H"""
# <.live_component id="test-lc" panel={@panel} module={HooksTestWeb.TestLiveComponent} />
# """
# end
@impl true
def render(%{panel: 1} = assigns) do
~H"""
<div id="panel1" phx-hook="Hook1" class="mt-2 p-2 border-2">
<.panel panel="1" />
</div>
"""
end
def render(%{panel: 2} = assigns) do
~H"""
<div id="panel2" phx-hook="Hook2" class="mt-2 p-2 border-2">
<.panel panel="2" />
</div>
"""
end
def panel(assigns) do
~H"""
<div><%= "Panel #{@panel}" %></div>
<button class="mt-2 p-1 border-2" phx-click="panel1">Panel 1</button>
<button class="mt-2 p-1 border-2" phx-click="panel2">Panel 2</button>
"""
end
@impl true
def handle_event("panel1", _, socket) do
{:noreply, assign(socket, panel: 1)}
end
def handle_event("panel2", _, socket) do
{:noreply, assign(socket, panel: 2)}
end
end
Actual behavior
Browser console displays Hook1 mounted
on initial render, nothing when buttons are clicked.
Expected behavior
Browser console displays Hook1 mounted
and Hook2 mounted
when the corresponding button is clicked.