Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

phx-viewport-bottom doesn't get triggered if there's a hidden element #3639

Open
jgcardelus opened this issue Jan 17, 2025 · 2 comments
Open

Comments

@jgcardelus
Copy link

Environment

  • Elixir version (elixir -v): 1.17.2
  • Phoenix version (mix deps): 1.7.18
  • Phoenix LiveView version (mix deps): 1.0.2
  • Operating system: macOS Sequoia 15.2
  • Browsers you attempted to reproduce this bug on (the more the merrier): Arc
  • Does the problem persist after removing "assets/node_modules" and trying again? Yes/no: Yes

Actual behavior

phx-viewport-bottom does not work if there's a hidden element (for example to show no results)

If you create an infinite scroll list with streams, set phx-bottom-viewport and add a hidden div (for example, to show no results as shown in the examples: Handling the empty case), the event doesn't get triggered when the last element reaches the bottom.

Reaching the end of the list won't trigger "next":

  def render(assigns) do
    ~H"""
    <div class="flex flex-col h-full w-full justify-center items-center">
      <div
        id="test"
        phx-update="stream"
        phx-viewport-bottom="next"
        phx-viewport-top="prev"
        class="w-[300px] h-[300px] max-h-[300px] overflow-y-auto bg-white border border-outline"
      >
        <div class="hidden empty:block" id="emtpy-container">
          <p>No results</p>
        </div>
        <div :for={{id, option} <- @streams.options} id={id}>
          <p>{option.name}</p>
        </div>
      </div>
    </div>
    """
  end

Image

Project with reproducible bug -> Navigate to "/" to see the example. The bug disappears when commenting the hidden div.

Expected behavior

When the user reaches the end of the list, phx-viewport-bottom get's triggered

Notes

I looked at LiveView's InfiniteScroll Hook and this.el.lastElement is being set to the hidden div, but it's boundingRect is

{
    "x": 0,
    "y": 0,
    "width": 0,
    "height": 0,
    "top": 0,
    "right": 0,
    "bottom": 0,
    "left": 0
}

and so isAtViewportBottom never returns true.

A possible fix would be to find the last element whose computed style for display is not none.


As a side note, I also think that phx-viewport-bottom should be triggered if the height of the items is less than the height of the container because some times in infinite lists, the container is bigger than the initially loaded items.

For example, let's say the container holds 50 items and you only load 30 out of 60. Since the last element will never reach the end of the container, the last 30 items are never loaded and the user has no way of loading them. I think it would make sense, in this case, to call viewport-bottom to immediately load the next 30, and keep doing it until either there are no more elements or the elements overflow the container.

@SteffenDE
Copy link
Collaborator

This is an issue, but I'm not sure yet how to best address it. We look for the first / last child in a scroll event handler, so the code we execute should be as minimal as possible. Checking possibly many items for visibility doesn't feel good to me :(

@jgcardelus
Copy link
Author

Yes, I agree with you that iterating over all the children doesn't feel good.

What about checking for the difference between the scroll position and the inner height of the overflowed component? I imagine there's a reason for the fact that the current implementation doesn't do it this way, but to me it seems like good way of doing it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants