How to run a `handle_event` defined in a `live_component` with `phx-click`?

How can I run the handle_event("open") function defined in MyAppWeb.LiveModal with a button defined in MyAppWeb.Index? I have tried using target, but it does not even print “open sesame”.

defmodule MyAppWeb.Index do
...

def render(assigns) do
  <button
        phx-click={JS.push("open", target: "#modal")}
        id="modal-btn"
      >
        Invite
  </button>
  <.live_component module={CollaborlistWeb.Live.InviteModal} id="modal" />
end

...
defmodule MyAppWeb.LiveModal do
  use CollaborlistWeb, :live_component

  @impl true
  def mount(socket) do
    {:ok, socket |> assign(open: false)}
  end

  @impl true
  def handle_event("open", _, socket) do
    IO.puts("open sesame")
    {:noreply, assign(socket, open: true)}
  end

  @impl true
  def render(assigns) do
    ~H"""
    <div>
      <%= if @open do %>
        OPEN
      <% else %>
        CLOSED
      <% end %>
    </div>
    """
  end
end

Did you try?

defmodule MyAppWeb.Index do
...

def render(assigns) do
  <button phx-click="open" phx-target="#modal" id="modal-btn">
    Invite
  </button>
  <.live_component module={CollaborlistWeb.Live.InviteModal} id="modal" />
end
...

Whatever, your solution should work too.
I’m wondering if the target should be modal instead of #modal :thinking:

1 Like

I tried your suggestion of using phx-target, and nothing is printed out still.

I also tried changing it to target:"modal", and that did not work either.

If this is supposed to be working, I wonder if something more nefarious is going on.

No javascript error in the console? (like the LiveView socket disconnecting)
Did you try to turn your light on & off three times in a row ? … it helps sometimes :man_shrugging:

1 Like

No errors. I even defined the button in the LiveView to make sure that the setup there is correct, and "OPEN" changed to "CLOSED" as expected.

defmodule MyWebApp.LiveModal
...
  def render(assigns) do
  ~H"""
    <div>
      <button
        phx-click={JS.push("open", target: @myself)}
        id="modal-btn"
        style="display:inline-block; float:right;"
      >
        Invite
      </button>

      <%= if @open do %>
        OPEN
      <% else %>
        CLOSED
      <% end %>
    </div>
    """
  end

I’m sorry, I have no clue on what’s going on.
I hope someone else will be able to help

1 Like

Just another idea: if you’re passing #modal as an ID (which is a DOM id), maybe should you have a DOM element with this id.

defmodule MyAppWeb.LiveModal do
  use CollaborlistWeb, :live_component
  def render(assigns) do
    ~H"""
    <div id="modal">
      ...
    </div>
    """
  end
end

I know that phx-target can either take DOM ids or LiveComponent CID, which might be confusing.

1 Like

Thank you! putting the id in the actual LiveComponent worked.

1 Like

I forget where, but in the LiveComponent docs it mentions that an id passed to the live_component function is used for tracking in in the socket, but it sets the id assign in the component so you can choose to also use it on the root function. You don’t have to hardcode it

1 Like