Passing Phoenix partial components into the model?

Hi all,

I have a modal div that I would like to share across multiple pages, so ideally, I’d like to be able to pass partial components into the modal. I’d like to achieve something like this:

# layout/_modal.html.eex
<div class="modal"
x-show="<%= @toggle_variable %>"
@click="<%= @toggle_variable %>=false"
>

...
<%= @inner_content %>
...
</div>

# _sign-in.html.eex
<%= render "_modal.html" toggle_variable: "signin", inner_content: ??? %>
# ideally I'd like the rest of this file to be the inner content itself


# main.html.eex
<div class="main">
...
<%= render "_sign-in.html" %>
...
</div>

Is that possible to achieve?

Many thanks! :slight_smile:

Hi @IVR if I understood your question, I think you could do something like this:

def render_modal(do: block) do
  # content assign to be called as @content inside modal template
  render(ModalView, "_modal.html", content: block) 
end

And then call it like this:

<%= render_modal do %>
   My Content
<% end %>
1 Like

Hey, thanks for the suggestion!

It does indeed look like what I’m looking for. Unfortunately, I’m lacking details here. How would you recommend to use this function? Here is what I’ve tried to do: I created a modal_controller.ex with your function, then I also created a modal_view.ex and a _modal.html.eex with a structure like this:

<div>
...
<% @content %>
...
</div>

Then I tried calling it from another html.eex file as you suggested, but I’m getting an error: undefined function render_modal/1, which is actually what I was partially expecting to see.

What am I missing here?

You would usually want to do something like this:

defmodule MyAppWeb.ModalView do
  use MyAppWeb, :view

  def render_modal(do: block) do
    render("_modal.html", content: block) 
  end
end

In your my_app_web/templates/modal/_modal.html:

<div class="modal">
  <h4 class="modal-header">Hello World</h4>
  <div class="modal-body"><%= @content %><div>
<div>

And then in the place you actually want to render the modal you’d call the view function:

<%= MyAppWeb.ModalView.render_modal do %>
   <button>Click Me!</button>
<% end %>

The important part is that you can pass a block to a function and this block can be passed as an assign to your templates through Phoenix.View.render/2 or Phoenix.View.render/3 (like in my first example).

It also helps if you get familiarized with how views work in Phoenix: Phoenix.View — Phoenix v1.5.8, because you end up using it a lot for things like this.

2 Likes

Excellent, it works, thank you!