Actually, instead of using the stream (proposed by default when using a generator), I use a classic assign {:ok, assign(socket, :items, list_items())} as the list is not too large. But it looks a bit frustrating that such a classic task makes so much trouble ![]()
Since you are using the classic assign and assuming list_items() always returns a list, you could conditionally show/hide with something like this:
<.table :if={Enum.any?(@items)} ...>...</.table>
<span :if={Enum.empty?(@items)}>No Articles</span>
Unless something has changed very recently, the generator is coded in a way that works with both a stream or a regular list. Perhaps the with line at the top of the table component that is confusing? The case version would look like this:
assigns =
case assigns do
%{rows: %Phoenix.LiveView.LiveStream{} ->
assign(assigns, row_id: assigns.row_id || fn {id, _item} -> id end)
assigns ->
assigns
end
I was experimenting with a similar setup and I was having the same problem, adding an id to the empty placeholder block (in your case, the .empty component) fixed the issue
This CSS trick works for my use case.
My try:
<ul phx-update="stream">
<li class="hidden last:block">
No items here.
</li>
<li :for={{dom_id, item} <- @streams.items} id={dom_id}>
...
</li>
</ul>
However, even if it works, my tests fail with:
30) test something (MyApp.MyTest)
test/my_app_web/live/my_liveview_test.exs:32
** (EXIT from #PID<0.1200.0>) an exception was raised:
** (ArgumentError) setting phx-update to "stream" requires setting an ID on each child. No ID was found on:
<li class="hidden last:block">
No items here.
</li>
(phoenix_live_view 0.19.5) lib/phoenix_live_view/test/dom.ex:520: anonymous fn/3 in Phoenix.LiveViewTest.DOM.apply_phx_update_children_id/2
(elixir 1.15.5) lib/enum.ex:2510: Enum."-reduce/3-lists^foldl/2-0-"/3
(phoenix_live_view 0.19.5) lib/phoenix_live_view/test/dom.ex:518: Phoenix.LiveViewTest.DOM.apply_phx_update_children_id/2
(phoenix_live_view 0.19.5) lib/phoenix_live_view/test/dom.ex:397: Phoenix.LiveViewTest.DOM.apply_phx_update/4
(floki 0.34.3) lib/floki/traversal.ex:6: anonymous fn/3 in Floki.Traversal.traverse_and_update/2
(floki 0.34.3) lib/floki/traversal.ex:18: Floki.Traversal.traverse_and_update/3
(floki 0.34.3) lib/floki/traversal.ex:23: Floki.Traversal.traverse_and_update/3
(floki 0.34.3) lib/floki/traversal.ex:37: Floki.Traversal.traverse_and_update/3
(floki 0.34.3) lib/floki/traversal.ex:18: Floki.Traversal.traverse_and_update/3
(floki 0.34.3) lib/floki/traversal.ex:23: Floki.Traversal.traverse_and_update/3
(floki 0.34.3) lib/floki/traversal.ex:37: Floki.Traversal.traverse_and_update/3
(floki 0.34.3) lib/floki/traversal.ex:18: Floki.Traversal.traverse_and_update/3
(floki 0.34.3) lib/floki/traversal.ex:23: Floki.Traversal.traverse_and_update/3
(floki 0.34.3) lib/floki/traversal.ex:37: Floki.Traversal.traverse_and_update/3
(floki 0.34.3) lib/floki/traversal.ex:18: Floki.Traversal.traverse_and_update/3
(floki 0.34.3) lib/floki/traversal.ex:37: Floki.Traversal.traverse_and_update/3
(floki 0.34.3) lib/floki/traversal.ex:18: Floki.Traversal.traverse_and_update/3
(floki 0.34.3) lib/floki/traversal.ex:23: Floki.Traversal.traverse_and_update/3
(floki 0.34.3) lib/floki/traversal.ex:6: Floki.Traversal.traverse_and_update/2
(phoenix_live_view 0.19.5) lib/phoenix_live_view/test/dom.ex:299: Phoenix.LiveViewTest.DOM.patch_id/4
I’m looking for a way to say to my liveview that I have a static (and so without ID) DOM element in my <ul phx-update="stream">. I didn’t find yet. Maybe it just doesn’t exists for now ![]()
I’m surprised nobody already mentions this issue here ![]()
This happen after an update from v0.18.18 to v0.19.5 of phoenix_live_view.
Edit: my workaround for now is using <li class="hidden last:block" id="untracked">, not sure it’s a good idea ![]()
How did the :empty psuedoselector fail you? Does the code below suit your needs?
<style>
/* Target contains children */
.track-empty > .track-empty__target + .track-empty__message { display: none; }
/* Target contains no children */
.track-empty > .track-empty__target:empty { display: none; }
.track-empty > .track-empty__target:empty + .track-empty__message { display: block; }
</style>
<div class="track-empty">
<ul class="track-empty__target" phx-update="stream">
<li :for={{dom_id, item} <- @streams.items} id={dom_id}>...</li>
</ul>
<div class="track-empty__message">
<p>No items here.</p>
</div>
</div>
I found this to be the most straightforward. I was hitting this error as well I guess the workaround is simply:
<.empty icon="clock-off" class="hidden only:block" id="insert-id-here">
<:title><%= dgettext("events", "No shifts") %></:title>
<:subtitle><%= dgettext("events", "There are no shifts for this event.") %></:subtitle>
</.empty>
This is a pretty old post, but it’s never too late to document more tricks… In case you want to do this from the parent and can’t rely on :empty (because of whitespaces), you can always use the :has() pseudo selector: <div phx-update="stream" class="hidden has-[div]:block"> (assuming your have divs inside of the parent)
.






















