Organising your Phoenix app into components

This is briefly covered in the Phoenix Guides.

What I do is similar to your (1) but I don’t add render functions in a view and call them directly.

I create a directory inside lib/my_app_web/templates which is usually named shared or partial and place the “shared” templates there. For this conversation I’ll just call it shared.

Create a template:

<%# lib/my_app_web/templates/shared/hello.html.eex %>

<strong>Hello <%= @name %>!</strong>

Then create the view:

# lib/my_app_web/views/shared_view.ex

defmodule MyAppWeb.SharedView do
  use MyAppWeb, :view

  # add any supporting functions for the shared templates
end

Then in any other template:

<%# lib/my_app_web/templates/page/index.html.eex %>

...
<%= render MyAppWeb.SharedView, "hello.html", name: "world" %>
...

Hello world!

If you want to nest directories under lib/my_app_web/templates/shared like lib/my_app_web/templates/shared/components for organization you’ll need to add pattern: "**/*", to the view function in lib/my_app_web.ex like so:

...
def view do
  quote do
    use Phoenix.View,
      root: "lib/my_app_web/templates",
+     pattern: "**/*",
      namespace: MyAppWeb
     ...
  end
end
...

Then when you use a template that is nested just provide the relative path to the template in the render function like so:

<%# lib/my_app_web/templates/page/index.html.eex %>

...
<%= render MyAppWeb.SharedView, "components/modal.html", conn: @conn, arg1: @arg1 %>

<%# If you're needing to pass many params (args) to the shared templates like arg1: @arg1, arg2: @arg2 etc., you can use `assigns` instead %>
<%= render MyAppWeb.SharedView, "components/modal.html", assigns %>
...

Hope that helps.

3 Likes