Stream empty state - is there a way to check when a stream is empty?

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 :slight_smile:

1 Like

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>
1 Like

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

1 Like

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 :scream:

I’m surprised nobody already mentions this issue here :stuck_out_tongue_closed_eyes:

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 :sweat_smile:

1 Like

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>