This animation shows how a repeating inside a datagrid panel scrolls up when a sub-repeating panel inside the main repeating panel is updated.
Here is the code that updates the sub-repeating panel:
def item_description_click(self, sender, **event_args):
if not self.repeating_panel_1.items:
self.repeating_panel_1.items = anvil.server.call('get_...', ...)
self.repeating_panel_1.visible = not self.repeating_panel_1.visible
The first time one item is expanded, the form calls a server function to populate the sub-repeating panel.
The next time it will just toggle its visibility.
How do I prevent it from scrolling every time the server function is called?
will sender.scroll_into_view() work?
or repeating_panel_1.scroll_into_view()?
Mmmh… I just tried it and it does solve part of the problem: it makes sure that the item that is expanded is still visible. That’s an improvement.
But it always scrolls that item to the center of the window, even when it is already visible. The result is very jumpy: every item you expand it scrolls a little up or down (unless you are at the very top or at the very bottom of the list).
I would like for the list not to scroll at all.
what about something like this
Native Libraries
<script>
var tempScrollTop;
function getSetScrollPosition (reset_position) {
if (!reset_position) {
tempScrollTop = $(window).scrollTop();
} else {
$(window).scrollTop(tempScrollTop);
}
}
</script>
decorator
def maintain_scroll_position(func):
def wrap(*args, **kwargs):
js.call_js('getSetScrollPosition')
res = func(*args, **kwargs)
js.call_js('getSetScrollPosition', True)
return res
return wrap
use the decorator above the function that causes the jump…
@maintain_scroll_position
def item_description_click(self, sender, **event_args):
if not self.repeating_panel_1.items:
self.repeating_panel_1.items = anvil.server.call('get_...', ...)
self.repeating_panel_1.visible = not self.repeating_panel_1.visible
I have the same issue for a similar component and this post reminded me I needed to fix it.
I just tried this for my own issue and it worked…
4 Likes
That almost worked out of the box.
I modified it a little because my scrollbar is not on the main window and because I want to define the decorator in a Globals
module.
It doesn’t feel right to fix the unintentional scroll by scrolling back rather than by removing the unintentional scroll, but it works.
In the Globals
module:
def maintain_scroll_position(selector):
def wrap(func):
def wrapped_func(*args, **kwargs):
anvil.get_open_form().call_js('getScrollPosition', selector)
res = func(*args, **kwargs)
anvil.get_open_form().call_js('restoreScrollPosition', selector)
return wrapped_func
return wrap
In the form:
from .. import Globals
[...]
@Globals.maintain_scroll_position('.content')
def item_facility_click(self, sender, **event_args):
In Native Libraries:
<script>
var lastScrollTop = {};
function getScrollPosition(selector) {
lastScrollTop[selector] = $(selector).scrollTop();
}
function restoreScrollPosition(selector) {
$(selector).scrollTop(lastScrollTop[selector]);
}
</script>
3 Likes