Supporting non-scrolling container
What are your thoughts on supporting a non-scrolling container (well, more precisely, a container that doesn't have a set height and expands to the height of the content). Would have to then observe window's scroll, but I'm running into a few instances where design-wise it would be better for us not to have to put a list within a scrollable container.
I wouldn't mind working out a PR in my free time for this, just wanted to hear your thoughts.
I want to make sure I understand your question correctly. So, I'll re-phrase it in my own words.
It sounds like you have a list of items that may grow in size. Below that list, you have, for example, a footer that always appears below the list and will be pushed down the page (and below the "fold"/bottom of the viewport) as items are added to the list. The user would scroll up and down using the browser window's main scroll bar rather than an overflow:auto on the list view element itself.
I guess re-styling the list view would only address part of the problem. Unless I am missing something, the bigger adjustment would be tying the scroll event handling to the main window. My current use case is within an "app-like" UI where the main window should never scroll. But it'd be useful to explore support for a list view that works in the context of a scrolling page design.
Is this change small enough to be a config property on the current implementation? Or is it something that's better suited to be a small mixin?
Obviously, if I've misunderstood your idea (as often happens before I've had some coffee), please let me know. I am certainly open to suggestions and pull requests. Thanks.
You're spot on.
As far as mixin vs. config property I'm unsure.
I haven't dug very deep yet. But...one way of looking at it (maybe) is right now the calculation for what listview items to draw is based on (correct me if I'm wrong) the height of the listview and its internal scroll position. What happens if that listview extends beyond the viewport of the window? Currently, I think listview items are inserted past the viewport of the window, even though they don't have to be (not visible anyways). Perhaps - this can be rethought - and instead of inserting listview items based solely on the height of their listview, to also consider the viewport of the window and what items would actually be visible within the viewport. Then we could just tie scroll event handling to the main window as well (in addition to the current scroll event handling).
Does this make sense?
Good point. I suppose if the list view keeps getting taller, it'll decide to render more child listings --- which would defeat the performance gains offered by the list view.
This leads to 3 TODOS:
- Ensure list view styles can be adapted to allow list view height to grow past the bottom of the window
- Adjust height calculation to account for window/viewport height
- Observe viewport scrolling event instead of element scrolling event to determine when/how to recycle child listings
Anything else I am missing?
That sounds about right. I also think current height calculations might break because the height of the listview will be 0 without any elements in it (in _recalculateHeight)
Regarding point 1) - is this up to the implementer (if I were implementing listView in my app I need to make sure that the styles can be adapted..) or is this something that needs to be addressed in the repo itself?
Todo 1 should be left to the implementer. It's just a matter of making sure the Javascript doesn't apply any inline styles that force the implementer to use something less than ideal (e.g !important). I don't think any such styles are applied, but it's good to keep in mind.
The height of 0 might be a pitfall. It could also be addressed with some styling (e.g. min-height) or by overriding some of the default behavior.
But that's just a theory.
Somehow, this strikes me as having just enough potential differences to be best served by extending ListView as something like InlineListView.
Perhaps the height of 0 can be fixed by just assuming the height of totalHeight - since in this case that is what the height of the list view should be after inserting elements.
I might kindly disagree with extending ListView - I think that all of this can be fit into the current ListView without any breaking changes, and perhaps it will add some performance increase under specific use cases.
Here's why (please let me know if I'm missing something):
First, the biggest change that needs to be made is to adjust how it calculates what items should be displayed. The change here is that it shouldn't show any items that are outside of the viewport.
Second, we need to observe window scrolling as well as container scrolling - as scrolling the window adjusts what items could be visible within the viewport. Maybe they both can call the same method.
These two changes together wouldn't affect current ListView implementations - and I guess in some use cases, if you have a mixed layout that has a ListView with scrollbars and your page also scrolls, then ListView will still work great for you. These two changes would also increase performance in this case as it will only render items that exist within the viewport.
Lastly, there will be some minor changes that need to be made, such as with _recalculateHeight - I think that if we have an initial height of 0 we can probably assume that the height is the same as totalHeight
Am I making sense? There's a good chance I'm looking at all this too simply as well - I haven't dug too deeply into the code yet.
The current list view is pretty introverted. It pays attention to itself (its own height/scrolling/etc) and has no code to make it aware of what nearby elements or the window are doing.
Just based on feeling and theory alone, I imagine to make the list view behave as expected, it would need to have some idea of where it is located in relationship to the top and bottom of the window. For example, if the top of the list view is halfway down the page, how it uses the window's scroll position to calculate what items to show may differ from a list view that uses its own scrollTop. I would also be careful about adding/removing listings based on window scroll. This can cause listings to "flicker" in some cases. And (if the listings are taller than the visible area) at least one extra listing must be rendered "offstage" for the scrolling effect to appear seamless to the user. (That is, as one item scrolls out of view, the extra listing is scrolling into view.)
In any case, if it turns out making the list view more aware of its surrounding elements and scroll events is a lot simpler than I am imagining, it wouldn't be too much of an effort to incorporate that code back into the list view object itself. Extending the list view with the additional logic may provide some additional benefits like better default settings. And since I haven't gotten around to making any unit tests, an extension of list view seems less risky at the moment.
Please feel free to take a swing at it the way you think works best. I would be thrilled to see what you come up with and work from there.
Oh. One other potential benefit of doing this as a mixin: other views that need to respond to window scrolling may also benefit.
I've come across this scenario as well. It seems like it should be doable.
My one additional comment on this discussion would be to not limit this to window scrolling events. The user should specify a selector, node or view that is acting as the scrolling container, which could be the window or some other content section. That would then be used for binding the scroll event and calculating visibility.
I may take a crack at this for my own project, and if I'm successful I'll submit a PR.
I was able to achieve an inline-capable extension of the list view. I don't feel ready for a PR yet, but here's my approach for extending list view.
-
Specify a
scrollParentthat will act as the parent DOM node of the list that will actually be scrolling. -
Use the
scrollParentto calculate the height. I'm overriding_recalculateHeightto use thescrollParent.outerHeight()instead of the list height. This defines the viewable region based on the scrollParent's height, and takes care of making sure theheightattr is correct. -
Override
scrollTopto be a computed property that calculates the scrollTop based on the list offset top and scrollParent offset top. -
I ended up having to override
scrollToin order to account for the list's relative offset from the scrollParent. -
Finally, on
didInsertElementI bound a scroll event handler on thescrollParentthat simply passes the event obj on to theonScrollfunction.
That appears to take care of an inline list, properly recycling views, as well as the added scrollTo helper functions.
@jmonma I'm finally getting around to needing to implement this functionality on a project - is there anyway you'd mind sharing your work - even just pushing it to your own fork of emberella? Even if not PR ready, I'd like to compare to what I've been doing so far and see what I can improve upon.
@conrad-vanl My stuff is in a completely different environment and doesn't use coffee script. But I can post a gist of the inline-list file so you can see what's going on.
This is by no means finished, and my file has some requirejs stuff in there that you don't have to worry about. Should be enough to get some ideas on ways to do it though.
https://gist.github.com/jmonma/6facf0e68854e2ec1295#file-inline-list-js