I’d like to use Phoenix function component but without the HEEX code being part of the module’s code - the HTML template is pretty long to be included in the Elixir module itself and would make the navigation and editing expierence somewhat hard.
Is there any way I could render the HTML from an external .html.heex file from within the function body, please?
Something like this
defmodule DashboardWeb.Components.Navigation do
use Phoenix.Component
def main_navigation(assigns) do
# Render .html.heex file here instead of the ~H sigil
end
end
I haven’t found any information in the documentation or in the source code and I failed all of my tries rendering the file view Phoenix.View or LiveView or even via Phoenix.Template
In Phoenix.LiveComponent this was automatically done when the render function was not defined in the component module (via Phoenix.LiveView.Renderer.before_compile) but I can’t figure out how to elegantly do it in the function component world.
For the context: The reason I am migrating standard LiveView components to the function ones is that I’d like to reuse some of the templates in “dead views” as well - mainly the ones generated by phx gen.auth in Phoenix 1.6.0. The rest of the application is all in LiveView where I can stay with standard LiveView components.
Is my approach wrong? Should I just duplicate the templates and use standard Phoenix.View in the “dead view” part of the application?
defmodule VtmeetWeb.Component do
use Phoenix.Component
def avatar(assigns) do
Phoenix.View.render(VtmeetWeb.LiveView, "component/avatar.html", assigns)
end
end
May I see how the VtmeetWeb.LiveView module looks like, please? Is that some kind of “root” module for the whole application?
I’d like to use the Phoenix.Component outside of specific LiveView context (page) . Basically rendering it in the templates/layout/live.html.heex file like so:
Currently the components I used are within liveview. So I’ve not tried what you want to accomplish.
Here is my liveview module
defmodule VtmeetWeb.LiveView do
use VtmeetWeb, :subtemplate_view
end
and the subtemplate_view def within vtmeet_web.ex :
def subtemplate_view do
quote do
use Phoenix.View,
root: "lib/vtmeet_web",
namespace: VtmeetWeb,
pattern: "**/*"
# Import convenience functions from controllers
import Phoenix.Controller, only: [get_flash: 1, get_flash: 2, view_module: 1]
# Include shared imports and aliases for views
unquote(view_helpers())
end
end
Note the pattern which allow to find the template in subdirectories (maybe that’s what is missing in your case).
That somewhat helped but I am unable to render the template w/o a LiveView context as it needs @socket variable. Which means the function component in this form is unfortunately not usable in the dead layout (aka app.html.heex)
For now I decided to just duplicate the navigation HTML template for the non-LV part of the application.
This is an interesting approach, but I don’t think it’s right. It works ok for a single type of component with a single template, but as soon as I added multiple components, each with their own template, the compiler gave some strange errors saying the view module couldn’t be found.
It seems like there should be a simpler way, since stateful components have this behavior automatically.
I was also trying to separate HEEX from the .ex file. The main reason was because Visual Studio Code doesn’t seem to handle intellisense pretty well in my current setup.
Since that separation doesn’t seem to be supported right now… if anybody’s got intellisense to recognize CSS classes, I’d be interested in knowing which extensions your using… along with any extra configuration that you made to get there.
Yeah, unfortunately, I don’t have a solution for this either. One of my main concerns is that since the main idea is to split components per function instead of per module, the component organization started to become a problem.
@LostKobrakai I considered doing this but since @APB9785 commented that, there are issues with this approach I think we should wait for a proper solution.