Hi!
This is my first post here. First of all, i appriciate for this community. I read posts here all day, and learned so much. Thank you!
I was looking forward to the new Phoenix version, so I could finally start my new project.
Iām a bit stuck. But I donāt know if thereās even a description of this anywhere in the documentation.
I would like create a dynamic drawer menu. The menu items could come from this list:
def main_menu do
[
%{id: "home", name: "Home", icon: &Heroicons.home/1, to: "/"},
%{id: "invoices", name: "Invoices", icon: &Heroicons.list_bullet/1, to: "/invoices"},
%{id: "partners", name: "Partners", icon: &Heroicons.users/1, to: "/partners"},
%{id: "products", name: "Products", icon: &Heroicons.archive_box/1, to: "/products"},
%{id: "settings", name: "Settings", icon: &Heroicons.adjustments_vertical/1, to: "/settings"},
]
end
I loop through this list and try to display:
attr :menu, :list, default: Drawer.main_menu(), doc: "list of menu items"
def drawer_menu(assigns) do
~H"""
<%= for item <- @menu do %>
<li>
<a href={item.to}>
<%= item.name %>
</a>
</li>
<% end %>
"""
end
I would like to show the Heroicon above the name, but i donāt know how could i achive this. I tried with <%= %>, but thrown error. <% %> also donāt work.
Some idea? Thank you!
Do those icons return heex or are they components themselves? <%= item.icon.() %> might work if itās heex, otherwise component can be used for dynamic components.
pro: itās vastly easier to deal with future requests like ācan we make just the users icon a little biggerā (by passing options to Heroicons.users) or ācan we make one word of the name in this menu item boldā (by adding markup directly to the name)
pro: itās trivial to add things like separators between groups of items, since the contents of the ul are just markup
con: itās a little more verbose, especially with long closing tags like </.drawer_menu_item>
con: if something else needs the structured data from main_menu, this makes for bad duplication
Same with <% item.icon.() %>
It would be nice to have a solution like svelte:component.
I think i will choose the solution of @al2o3cr . I havenāt had time to try it yet. When itās done, Iāll come back and check it as solution.
Thank you for your replies.
With <%= ⦠/>, got this: &Heroicons.home/1 with arity 1 called with no arguments
If i pass arguments, then the assigns map is missing.
I tried also:
def drawer_menu(assigns) do
assigns =
assigns
|> Map.put(:solid, :true)
|> Map.put(:class, "h-5 w-5")
~H"""
<%= for item <- @menu do %>
<li>
<a href={item.to}>
<%= item.icon.(assigns) %>
<%= item.name %>
</a>
</li>
<% end %>
"""
end
Got this: lists in Phoenix.HTML and templates may only contain integers representing bytes, binaries or other lists, got invalid entry: %{icon: &Heroicons.home/1, id: āhomeā, name: āHomeā, to: ā/ā}
Thing to add - you donāt need to convert strings to atoms (in icon/1) and you could pass the atom directly from the template, e.g <.icon name={:document_text}> but I prefer this way as itās a simpler for front-end folks to operate on strings.