I love the explicit syntax with attr for function components. Are we ever going to get declarative assigns like this for live components? That would be sweeeeeeet .
Iām not sure but I always make a āconstructorā function component:
defmodule MyAppWeb.FooComponent do
use MyAppWeb, :live_component
attr :id, :string, required: true
attr :foo, :string
attr :bar, :string
def live_foo(assigns) do
~H"""
<.live_component
module={__MODULE__}
id={@id}
foo={@foo}
bar={@bar}
/>
"""
end
end
Not does this let you use declarative assigns, it cleans up the callsites. I always prefix with live_
so itās obvious they are live components but itās not necessary.
I know Iām not the only one who does this!
Interesting idea, suppose you could also make this into a macro as well as splat the assigns out. Any downsides though?
I believe that would break change-tracking, though there may be a way to make it work.
According to documentation:
To interpolate a dynamic number of attributes in a keyword list or map, do:
<div title="My div" {@many_attributes}> <p>Hello <%= @username %></p> </div>
It should be very easy to do so:
defmodule MyAppWeb.FooComponent do
use MyAppWeb, :live_component
props :props_assigns do
attr :id, :string, required: true
attr :foo, :string
attr :bar, :string
end
def live_foo(assigns) do
~H"""
<.live_component module={__MODULE__} {@props_assigns} />
"""
end
end
Here is what needs to be done to make it work:
- Create
props/2
macro which groups assigns using a specified key - Create
attr/3
macro which puts an desired attribute into currentprops
(if any) and calls backLiveView
ās macro - Create
def/2
macro which collect assigns from props groups, removes them from original assigns, puts groups under a key specified inprops/2
macro call and finally calls backLiveView
ās macro
Oh, reassigning and splatting is a good idea!
I never have too many options for live components so I wouldnāt bother with a DSL like this myself, but if it became part of Phoenix Iād use it.
This is unlikely to happen given live components do not get assigns just from the tag theyāre rendered with, but also from send_update
calls. For the tag based inputs a wrapper function component is imo the best solution.
This is how I do it to all my live components:
defmodule MyAppWeb.FooComponent do
use MyAppWeb, :live_component
attr :id, :string, required: true
attr :foo, :string
attr :bar, :string
def live_render(assigns), do: ~H"<.live_component module={__MODULE__} {assigns} />"
end
Basically the same thing as the example @sodapopcan showed, but I pass the assigns directly so I donāt need to explicitly pass them all.
This will break change-tracking as far as I know, though.
I donāt think it does, at least if it does I never noticed it in more than 300 components I have with it haha
Btw, this is how LiveDashboard handles live components too phoenix_live_dashboard/lib/phoenix/live_dashboard/page_builder.ex at d1578d877a99e0f31eb6384201f4bbd7239e4028 Ā· phoenixframework/phoenix_live_dashboard Ā· GitHub
Hmmm ya, it doesnāt seem to and now I just got your second response, so interesting! Perhaps this applies to what is described near the bottom of this section. While it says you should never splat assigns, you can pass them into a function if you need to forward them along, so I suppose that is whatās happening here and itās ok because there is just one instance of it in the component? Being able to splat assigns here is much better IMO, not just because itās more convenient but it removes duplication that provides no extra value (unless you arenāt using declarative assigns for some reason). In any event, this should be documented as to where this works and why. Otherwise using it in a shared codebase sorta sets a poor precedent that it is generally ok.
Thanks for pointing this out!
Iāve wrapped live components in functional components to gain props for a bit, but ultimately stopped since I thought the functional fake mask created a dangerous false identity for what is going on and could confuse people who donāt have intimate knowledge of the system.
I would love it if we could get some kind of prop help from the framework for live component. The current situation does not seem ideal.
This is exactly why I always prefix them with live_
.