Closed markquezada closed 1 year ago
Can you please update the code to check it is a string and raise otherwise? And update the docs too? PR welcome. :)
I made a stab at this and ran into several problems, mostly due to my not reading through it fully.
push_navigate
, not on initial page load...so it might be warranted an actual "fix"
The initial page load actually renders a class list space-separated as one would expect. I verified this with a test, and manually. More details on what I actually did (nothing worth committing) further down.
It's only when you push_navigate or click a link with a redirect, when this happens
More specifically, the issue gets created in dom.js
, in replaceRootContainer
container.setAttribute(attrs, ['foo','bar'])
will convert the array to a comma-separated string
I assume that's not where we want to fix it (or do we?), so we'd have to be converting to string from list on the backend. Some surface level investigation shows this could be done in channel.ex, in put_container/3
Or, possibly, some caller of that function.
A quick and dirty fix would look something like, but I'm sure it could be nicer.
defp put_container(%Session{} = session, %Route{} = route, %{} = diff) do
if container = session.redirected? && Route.container(route) do
{tag, attrs} = container
attrs = Enum.into(attrs, %{})
attrs =
case attrs[:class] do
nil -> attrs
c when is_binary(c) -> attrs
c when is_list(c) -> Map.put(attrs, :class, Enum.join(c, " "))
end
Map.put(diff, :container, [tag, attrs])
else
diff
end
end
To me, this kind of makes sense, as providing class lists is kind of a thing in some frameworks out there, and Phoenix.HTML.tag/content_tag
, already accepts a list as class attribute, as does the initial backend-based renderer for live view, as a consequence.
The one place where I see the container option getting validated is maybe a bit too generic and we'd have to get quite specific with the class
But then, would a string value have to be enforced on all attributes here, or only for the class, or a subset?
Alternatively, something could maybe be done in the before_compile
of phoenix_live_view.ex
, but there is no such validation there currently.
DOM.to_html({"span", [{"class", ["foo", "bar"]}], []})
this outputs <span class="foobar"></span>
. So it's not comma-separated but rather joined using empty string. This is directly calling floki and I'm not really sure if it's standard or should be considered a bug.
When using the
container:
option whenuse
ing liveview, we mistakenly used a list for multiple class names, like so:The docs show it as a string but does not explicitly state it has to be. Since heex accept lists of classes for tags, we mistakenly used a list instead of a string and saw odd results.
Environment
Elixir 1.14.0 (compiled with Erlang/OTP 25)
phoenix 1.7.0-rc.2
phoenix_live_view 0.18.11
Actual behavior
When the dom is updated via a
push_navigate
, the classes were joined with a comma on the live view container. E.g.:h-full,overflow-hidden,print:overflow-visible
Expected behavior
The classes should be rendered with spaces, e.g.:
"h-full overflow-hidden print:overflow-visible"
Or, the docs should be updated to explicitly state a string is required.