Skip to content

Commit

Permalink
Ensure ReactiveHTML correctly resets Event parameters (#6247)
Browse files Browse the repository at this point in the history
* Ensure ReactiveHTML correctly resets Event parameters

* Add test

* Further fixes

* Update test
  • Loading branch information
philippjfr authored Jan 20, 2024
1 parent 8e7992a commit 2a892a3
Show file tree
Hide file tree
Showing 4 changed files with 45 additions and 5 deletions.
2 changes: 2 additions & 0 deletions panel/models/reactive_html.py
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,8 @@ class ReactiveHTML(HTMLBox):

events = bp.Dict(bp.String, bp.Dict(bp.String, bp.Bool))

event_params = bp.List(bp.String)

html = bp.String()

looped = bp.List(bp.String)
Expand Down
8 changes: 7 additions & 1 deletion panel/models/reactive_html.ts
Original file line number Diff line number Diff line change
Expand Up @@ -169,9 +169,13 @@ export class ReactiveHTMLView extends HTMLBoxView {
const property = data_model.properties[attr]
if (property == null)
continue
const is_event_param = this.model.event_params.includes(prop)
this.connect(property.change, () => {
if (!this._changing)
if (!this._changing && !(is_event_param && !data_model[prop])) {
this.run_script(prop)
if (is_event_param)
data_model.setv({[prop]: false})
}
})
}
}
Expand Down Expand Up @@ -503,6 +507,7 @@ export namespace ReactiveHTML {
callbacks: p.Property<any>
children: p.Property<any>
data: p.Property<any>
event_params: p.Property<string[]>
events: p.Property<any>
html: p.Property<string>
looped: p.Property<string[]>
Expand All @@ -529,6 +534,7 @@ export class ReactiveHTML extends HTMLBox {
callbacks: [ Any, {} ],
children: [ Any, {} ],
data: [ Any, ],
event_params: [ Array(String), [] ],
events: [ Any, {} ],
html: [ String, "" ],
looped: [ Array(String), [] ],
Expand Down
13 changes: 10 additions & 3 deletions panel/reactive.py
Original file line number Diff line number Diff line change
Expand Up @@ -1669,23 +1669,27 @@ def _init_params(self) -> Dict[str, Any]:
p : getattr(self, p) for p in list(Layoutable.param)
if getattr(self, p) is not None and p != 'name'
}
data_params = {}
data_params, event_params = {}, []
for k, v in self.param.values().items():
pobj = self.param[k]
if (
(k in ignored and k != 'name') or
((self.param[k].precedence or 0) < 0) or
(isinstance(v, Viewable) and not isinstance(self.param[k], param.ClassSelector))
((pobj.precedence or 0) < 0) or
(isinstance(v, Viewable) and not isinstance(pobj, param.ClassSelector))
):
continue
if isinstance(v, str):
v = HTML_SANITIZER.clean(v)
data_params[k] = v
if isinstance(pobj, param.Event):
event_params.append(k)
html, nodes, self._attrs = self._get_template()
params.update({
'attrs': self._attrs,
'callbacks': self._node_callbacks,
'data': self._data_model(**self._process_param_change(data_params)),
'events': self._get_events(),
'event_params': event_params,
'html': escape(textwrap.dedent(html)),
'nodes': nodes,
'looped': [node for node, _ in self._parser.looped],
Expand Down Expand Up @@ -1994,6 +1998,9 @@ def _update_model(
model_msg['children'] = children
self._set_on_model(model_msg, root, model)
self._set_on_model(data_msg, root, model.data)
reset = {p: False for p in data_msg if p in model.event_params}
if reset:
self._set_on_model(reset, root, model.data)

def on_event(self, node: str, event: str, callback: Callable) -> None:
"""
Expand Down
27 changes: 26 additions & 1 deletion panel/tests/ui/test_reactive.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,16 @@ class ReactiveComponent(ReactiveHTML):

count = param.Integer(default=0)

event = param.Event()

_template = """
<div id="reactive" class="reactive" onclick="${script('click')}"></div>
"""

_scripts = {
'render': 'data.count += 1; reactive.innerText = `${data.count}`;',
'click': 'data.count += 1; reactive.innerText = `${data.count}`;'
'click': 'data.count += 1; reactive.innerText = `${data.count}`;',
'event': 'data.count += 1; reactive.innerText = `${data.count}`;',
}

class ReactiveLiteral(ReactiveHTML):
Expand All @@ -46,6 +49,28 @@ def test_reactive_html_click_js_event(page):

wait_until(lambda: component.count == 2, page)

def test_reactive_html_param_event(page):
component = ReactiveComponent()

serve_component(page, component)

expect(page.locator(".reactive")).to_have_text('1')

component.param.trigger('event')

expect(page.locator(".reactive")).to_have_text('2')

component.param.trigger('event')

expect(page.locator(".reactive")).to_have_text('3')

component.param.trigger('event')
component.param.trigger('event')

expect(page.locator(".reactive")).to_have_text('5')

wait_until(lambda: component.count == 5, page)

def test_reactive_html_set_loading_no_rerender(page):
component = ReactiveComponent()

Expand Down

0 comments on commit 2a892a3

Please sign in to comment.