defmodule MyProjectWeb.Navbar do
use Phoenix.Component
def navbar(assigns) do
~H"""
<div class="navbar bg-primary">
<a href={~p"/"}>Home</a>
</div>
"""
end
end
When I do this I get a compile error
“(CompileError) undefined function sigil_p/2 (expected MyProjectWeb.Navbar to define such a function or for it to be imported, but none are available)”
Am I doing something wrong, or is this not possible?
Using Phoenix 1.7.0-rc-2, I get the following warning when attempting to use the workaround mentioned above. Switching out use Phoenix.Component with use TodoListWeb, :html results in this error:
(UndefinedFunctionError) function TodoListWeb.BaseComponents.module_info/1 is undefined (function not available)
(todo_list 0.1.0) TodoListWeb.BaseComponents.module_info(:exports)
Stacktrace:
│ (elixir 1.14.2) src/elixir_import.erl:98: :elixir_import.calculate/6
│ (elixir 1.14.2) src/elixir_import.erl:28: :elixir_import.import/4 (Elixir)
Funny enough I just ran into the same issue for the first time just now, about 2 hours later.
I think your and my issue are the same - that we’re trying to create our components in a module that is also included in the html_helpers macro that html unquotes. So you end up with a circular reference.
In RobinBeekhof’s original question, he’s doing this in a singular module MyProjectWeb.Navbar, so it wouldn’t be included as a core component and create the import loop.
I ended up fixing it by creating an extra helper in my myapp_web.ex, called html_helpers_plus which looks like this:
defp html_helpers_plus do
quote do
use Phoenix.Component
# Include general helpers for rendering HTML
unquote(html_helpers())
# Custom application components using verified routes
import MyAppWeb.AppComponents
end
end
I.e. it just unquotes html_helpers and then imports my app components that want to use verified routes. That way in AppComponents I can have the use MyAppWeb, :html line and not get the circular dependency.
I then import that in the live_view macro defined in the same file:
def live_view do
quote do
use Phoenix.LiveView,
layout: {MyAppWeb.Layouts, :app}
unquote(html_helpers_plus())
end
end
and then any of my live views can automatically access the verified routes using components.
In dead views you can still import the components directly in the xyz_html.ex before the embed_templates call.
I’d love to know if there is a more elegant way to solve the issue though