How to use a form_component from another live view?

I have two schemas (User and Post) in separate contexts with auto-generated live views for each and associated with a typical user has_many posts relation

Creating/editing a new Post via app/posts (i.e. post_live/index.html.leex) works fine (as well as associating with current user).

But, I’d like to let users create posts from their profile (i.e. user_live/show.html.leex). So, I tried to pass the PostLive.FormComponent to the live_modal as usual:

<%= live_patch "+New Post", to: Routes.user_show_path(@socket, :new_post, @user) %>

<%= if @live_action in [:new_post] do %>
  <%= live_modal @socket, App.PostLive.FormComponent,
    id: @post.id || :new,
    title: @page_title,
    action: @live_action,
    post: @post,
    return_to: Routes.user_show_path(@socket, :posts, @user) %>
<% end %>

And added the action handler to the UserLive.Show module:

defp apply_action(socket, :new_post, _params) do
  socket
  |> assign(:page_title, "New Post")
  |> assign(:post, %Post{})
end

Problems:

  1. Closing the standard live_modal throws error:

** (FunctionClauseError) no function clause matching in App.UserLive.Show.handle_event/3
…UserLive.Show.handle_event(“close”, %{}…

But, why the handle_event("close", _, socket) in the App.ModalComponent isn’t triggered?
What am I missing here?

  1. SOLVED: Saving a post via UserLive.Show view doesn’t work (the form just hangs forever).
    looks like the “save” event is not handled by the handle_event("save", params, socket) in the PostLive.FormComponent.
    So, how do I create a new Post via the User liveview?

UPDATE:
The second issue is solved by adding correct action to action handler in the PostLive.FormComponent as:

defp save_post(socket, action, post_params) when action in [:new, :new_post]

You seem to be missing a phx-target attribute pointing the event to the correct component. How are you closing the modal?

Thanks for taking a look! I didn’t change the auto-generated Phoenix modal_component.ex, so it looks like:

defmodule AppWeb.ModalComponent do
  use AppWeb, :live_component

  @impl true
  def render(assigns) do
    ~L"""
    <div id="<%= @id %>" class="phx-modal"
      phx-capture-click="close"
      phx-window-keydown="close"
      phx-key="escape"
      phx-target="#<%= @id %>"
      phx-page-loading>

      <div class="phx-modal-content">
        <%= live_patch raw("&times;"), to: @return_to, class: "phx-modal-close" %>
        <%= live_component @socket, @component, @opts %>
      </div>
    </div>
    """
  end

  @impl true
  def handle_event("close", _, socket) do
    {:noreply, push_patch(socket, to: socket.assigns.return_to)}
  end
end

And this same component is used for other models too and works fine, i.e. closing and cancelling (click outside the modal form, or “Esc” key) does trigger the component’s handle_event("close"...).

However in the case stated above it throws that error. Any advice on how to debug this is very appreciated!

Check if the ModalComponent id is unique in the html markup code.

1 Like

Indeed, what a silly mistake ))
I had another (pure CSS) modal pop-up with id="modal" in one of the rendered partial components.
Brilliant catch, thank you so much!

1 Like