Skip to content

Commit 1347b69

Browse files
Allow defining an update method as part of an element's dictionary (#4470)
This PR solves #4344 by defining update methods as part of the element's dictionary which is sent to the client. This way nicegui.js can call such update methods directly and we don't have to call something like `runMethod('update_grid')` from Python. The following code caused multiple updates when clicking the button (analyzed with a console.log in aggrid.js): ```py grid = ui.aggrid({}) ui.button('update', on_click=lambda: grid.classes('foo').classes('bar').classes('baz')) ``` With this PR, all updates are consolidated and `update_grid` is only called once.
1 parent d87ee22 commit 1347b69

File tree

8 files changed

+16
-25
lines changed

8 files changed

+16
-25
lines changed

nicegui/element.py

+2
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ def __init__(self, tag: Optional[str] = None, *, _client: Optional[Client] = Non
6363
self._text: Optional[str] = None
6464
self.slots: Dict[str, Slot] = {}
6565
self.default_slot = self.add_slot('default')
66+
self._update_method: Optional[str] = None
6667
self._deleted: bool = False
6768

6869
self.client.elements[self.id] = self
@@ -197,6 +198,7 @@ def _to_dict(self) -> Dict[str, Any]:
197198
'slots': self._collect_slot_dict(),
198199
'children': [child.id for child in self.default_slot.children],
199200
'events': [listener.to_dict() for listener in self._event_listeners.values()],
201+
'update_method': self._update_method,
200202
'component': {
201203
'key': self.component.key,
202204
'name': self.component.name,

nicegui/elements/aggrid.py

+1-4
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ def __init__(self,
4545
self._props['html_columns'] = html_columns[:]
4646
self._props['auto_size_columns'] = auto_size_columns
4747
self._classes.append(f'ag-theme-{theme}')
48+
self._update_method = 'update_grid'
4849

4950
@classmethod
5051
def from_pandas(cls,
@@ -121,10 +122,6 @@ def options(self) -> Dict:
121122
"""The options dictionary."""
122123
return self._props['options']
123124

124-
def update(self) -> None:
125-
super().update()
126-
self.run_method('update_grid')
127-
128125
def run_grid_method(self, name: str, *args, timeout: float = 1) -> AwaitableResponse:
129126
"""Run an AG Grid API method.
130127

nicegui/elements/echart.py

+1-4
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ def __init__(self,
4343
self._props['options'] = options
4444
self._props['enable_3d'] = enable_3d or any('3D' in key for key in options)
4545
self._props['renderer'] = renderer
46+
self._update_method = 'update_chart'
4647

4748
if on_point_click:
4849
self.on_point_click(on_point_click)
@@ -104,10 +105,6 @@ def options(self) -> Dict:
104105
"""The options dictionary."""
105106
return self._props['options']
106107

107-
def update(self) -> None:
108-
super().update()
109-
self.run_method('update_chart')
110-
111108
def run_chart_method(self, name: str, *args, timeout: float = 1) -> AwaitableResponse:
112109
"""Run a method of the EChart instance.
113110

nicegui/elements/json_editor.py

+1-4
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ def __init__(self,
3434
"""
3535
super().__init__()
3636
self._props['properties'] = properties
37+
self._update_method = 'update_editor'
3738

3839
if schema:
3940
self._props['schema'] = schema
@@ -63,10 +64,6 @@ def properties(self) -> Dict:
6364
"""The property dictionary."""
6465
return self._props['properties']
6566

66-
def update(self) -> None:
67-
super().update()
68-
self.run_method('update_editor')
69-
7067
def run_editor_method(self, name: str, *args, timeout: float = 1) -> AwaitableResponse:
7168
"""Run a method of the JSONEditor instance.
7269

nicegui/elements/notification.py

+1-4
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ def __init__(self,
6666
"""
6767
with context.client.layout:
6868
super().__init__()
69+
self._update_method = 'update_notification'
6970
if options:
7071
self._props['options'] = options
7172
else:
@@ -211,7 +212,3 @@ def dismiss(self) -> None:
211212

212213
def set_visibility(self, visible: bool) -> None:
213214
raise NotImplementedError('Use `dismiss()` to remove the notification. See #3670 for more information.')
214-
215-
def update(self) -> None:
216-
super().update()
217-
self.run_method('update_notification')

nicegui/elements/plotly.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ def __init__(self, figure: Union[Dict, go.Figure]) -> None:
3737
self.figure = figure
3838
self.update()
3939
self._classes.append('js-plotly-plot')
40+
self._update_method = 'update'
4041

4142
def update_figure(self, figure: Union[Dict, go.Figure]):
4243
"""Overrides figure instance of this Plotly chart and updates chart on client side."""
@@ -46,7 +47,6 @@ def update_figure(self, figure: Union[Dict, go.Figure]):
4647
def update(self) -> None:
4748
self._props['options'] = self._get_figure_json()
4849
super().update()
49-
self.run_method('update')
5050

5151
def _get_figure_json(self) -> Dict:
5252
if isinstance(self.figure, go.Figure):

nicegui/elements/teleport.py

+1-8
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,4 @@ def __init__(self, to: Union[str, Element]) -> None:
1616
if isinstance(to, Element):
1717
to = f'#c{to.id}'
1818
self._props['to'] = to
19-
20-
def update(self) -> None:
21-
"""Force the internal content to be retransmitted to the specified location.
22-
23-
This method is usually called after the target container is rebuilt.
24-
"""
25-
super().update()
26-
self.run_method('update')
19+
self._update_method = 'update'

nicegui/static/nicegui.js

+8
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ function replaceUndefinedAttributes(element) {
2525
element.props ??= {};
2626
element.text ??= null;
2727
element.events ??= [];
28+
element.update_method ??= null;
2829
element.component ??= null;
2930
element.libraries ??= [];
3031
element.slots = {
@@ -386,6 +387,13 @@ function createApp(elements, options) {
386387
replaceUndefinedAttributes(element);
387388
this.elements[id] = element;
388389
}
390+
391+
await this.$nextTick();
392+
for (const [id, element] of Object.entries(msg)) {
393+
if (element?.update_method) {
394+
getElement(id)[element.update_method]();
395+
}
396+
}
389397
},
390398
run_javascript: (msg) => runJavascript(msg.code, msg.request_id),
391399
open: (msg) => {

0 commit comments

Comments
 (0)