Skip to content

Commit e311012

Browse files
Sub pages can be refreshed (zauberzeug#5192)
### Motivation If just some data changed (like setting another translation or similar), it is tricky to refresh `ui.sub_pages`. They will not react to `ui.navigate_to(ui.context.client.sub_pages_router.current_path)` because the path does not change and hence the re-evaluation is skipped. ### Implementation This PR introduces `refresh` methods for `ui.sub_pages` and `ui.context.client.sub_pages_router`. The first only refreshes itself and all nested sub pages elements. And the latter one refreshes all currently shown sub pages elements. ### Progress - [x] I chose a meaningful title that completes the sentence: "If applied, this PR will..." - [x] The implementation is complete. - [x] Pytests have been added. - [x] Documentation has been added. - [x] Update "Added in version ..." --------- Co-authored-by: Falko Schindler <[email protected]>
1 parent f8c7385 commit e311012

File tree

3 files changed

+64
-0
lines changed

3 files changed

+64
-0
lines changed

nicegui/elements/sub_pages.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,14 @@ def add(self, path: str, page: Callable) -> Self:
6767
self._show()
6868
return self
6969

70+
def refresh(self) -> None:
71+
"""Rebuild this sub pages element.
72+
73+
*Added in version 3.1.0*
74+
"""
75+
self._reset_match()
76+
self._show()
77+
7078
def _show(self) -> None:
7179
"""Display the page matching the current URL path."""
7280
self._rendered_path = ''

nicegui/sub_pages_router.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,19 @@ def on_path_changed(self, handler: Callable[[str], None]) -> None:
4949
"""
5050
self._path_changed_handlers.append(handler)
5151

52+
async def refresh(self) -> None:
53+
"""Refresh the currently shown sub pages.
54+
55+
This will clear and rebuild the current sub page as if navigating to it again.
56+
Useful when you want to update the page content based on changes in data or state.
57+
58+
*Added in version 3.1.0*
59+
"""
60+
for el in context.client.layout.descendants():
61+
if isinstance(el, SubPages):
62+
el._reset_match() # pylint: disable=protected-access
63+
await self._handle_open(self.current_path)
64+
5265
async def _handle_open(self, path: str) -> bool:
5366
self.current_path = path
5467
self.is_initial_request = False

tests/test_sub_pages.py

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1170,3 +1170,46 @@ def index():
11701170
screen.click('Delete')
11711171
screen.wait(0.5)
11721172
screen.should_not_contain('main page')
1173+
1174+
1175+
def test_refresh_sub_page(screen: Screen):
1176+
calls = {'index': 0, 'outer': 0, 'inner_main': 0, 'inner_other': 0}
1177+
1178+
@ui.page('/')
1179+
@ui.page('/{_:path}')
1180+
def index():
1181+
calls['index'] += 1
1182+
sub_pages = ui.sub_pages({'/': outer_page})
1183+
ui.button('Refresh via Router', on_click=ui.context.client.sub_pages_router.refresh)
1184+
ui.button('Refresh via SubPages', on_click=sub_pages.refresh)
1185+
1186+
def outer_page():
1187+
calls['outer'] += 1
1188+
ui.sub_pages({'/': inner_main, '/other': inner_other})
1189+
ui.link('Go to other', '/other')
1190+
1191+
def inner_main(args: PageArguments):
1192+
calls['inner_main'] += 1
1193+
ui.button('Refresh inner main', on_click=args.frame.refresh)
1194+
1195+
def inner_other(args: PageArguments):
1196+
calls['inner_other'] += 1
1197+
ui.button('Refresh inner other', on_click=args.frame.refresh)
1198+
1199+
screen.open('/')
1200+
assert calls == {'index': 1, 'outer': 1, 'inner_main': 1, 'inner_other': 0}
1201+
1202+
screen.click('Refresh inner main')
1203+
assert calls == {'index': 1, 'outer': 1, 'inner_main': 2, 'inner_other': 0}
1204+
1205+
screen.click('Go to other')
1206+
assert calls == {'index': 1, 'outer': 1, 'inner_main': 2, 'inner_other': 1}
1207+
1208+
screen.click('Refresh inner other')
1209+
assert calls == {'index': 1, 'outer': 1, 'inner_main': 2, 'inner_other': 2}
1210+
1211+
screen.click('Refresh via Router')
1212+
assert calls == {'index': 1, 'outer': 2, 'inner_main': 2, 'inner_other': 3}
1213+
1214+
screen.click('Refresh via SubPages')
1215+
assert calls == {'index': 1, 'outer': 3, 'inner_main': 2, 'inner_other': 4}

0 commit comments

Comments
 (0)