I’m currently updating the lists in my app to live streams and infinite scrolling as describe in liveview bindings documentation, and I want to handle the empty case.
Previously, I could display a message when the items list is empty, but it’s not possible anymore with streams, since they don’t implement count or empty.
There’s not, because without additional constraints there’s no way to know the current state of the stream on the server as it is observed on the client.
if you have infinite scrolling, then you necessarily have pagination for next/previous page, no? Then you can toggle an empty state assign as other have alluded to when you hit no results without having to check the existing stream contents.
Thinking out loud, this could be a good use case for the :first-child or :last-childpseudoselectors. This will let the browser determine how to display the empty list message based on whether there are any other streamed elements rendered.
I got an example working by adding the following line to the .table core component as the first <tr> before the streamed ones. You could also add it to the end and use the :first-child pseudoselector instead.
I have no pagination at all on my articles index template. I tried to apply your fix, but the message is displayed after deleting a single item and even if there is at least 1 item left.
I’m not @codeanpeace, I’m from that other thread and just butting in since we were talking there
The important bit to see is where you put it in the table component. Is it possible you put it outside the tbody or something or maybe have other modifications that would result in there being more than tr left even when there are no articles? I would inspect the DOM after deleting the last one and ensure there is only one tr left.
ops, my bad, I totally messed it up .
Here is how looks the table/1 function where I just added a single line like @codeanpeace did (inside tbody section):
Yep, that stands to reason since the CSS is based on the number of trs.
You can always use JS to hide if empty. If you don’t want to resort to JS you’ll have to try another method from this thread.
However, since you say you only have one page, you possibly don’t need a stream at all. If you hold all the articles in state then your original code (from the other thread) will work and this problem goes away. Streams are only necessary if you have very large amounts of data of an unknown size.
Yeah, when I first had the idea, I had <ul>/<ol> and <li> elements in mind where it would be much less of an issue or even desired behavior. I ended up applying the idea to the .table core component purely out of convenience since that was what was available in a newly generated Phoenix app.
I have the same issue as you (not for a <table> though, but with a list of <div>), and there’s a strange behavior when removing an item.
I have the following code:
<main
id="shift-list"
phx-update="stream"
>
<.empty icon="clock-off" class="hidden only:block">
<:title><%= dgettext("events", "No shifts") %></:title>
<:subtitle><%= dgettext("events", "There are no shifts for this event.") %></:subtitle>
</.empty>
<.live_component
:for={{id, shift} <- @streams.shifts}
id={id}
shift={shift}
/>
</main>
Both components are basically <div>. It works fine when there’s only one item or more, my empty state div is hidden, and the items are visible underneath: