panel
panel copied to clipboard
JS triggering of "loading" css_classes doesn't propagate to Python
I often want to set the loading state of some element with JavaScript:
btn = pn.widgets.Button(name='Load', button_type='primary')
btn.js_on_click(args={'btn': btn}, code='btn.css_classes.push("pn-loading", "arcs"); btn.properties.css_classes.change.emit();')
but then I want to reset it in Python. I assumed this this would be sufficient:
btn.css_classes = []
But setting css_classes to the empty list doesn't trigger a change, presumably because the change to css_classes wasn't propagated from the JS so Python sees it as still sees it as the empty list.
So I assumed that this would force the JS Bokeh model to reset:
btn.css_classes = []
btn.param.trigger('css_classes')
But it is also ineffective at resetting the loading state.
The only thing that I could get to work is to set css_classes to something else:
btn.css_classes = ['temp']
btn.css_classes = []
Here is a full example:
class Demo(param.Parameterized):
def load(self):
sleep(2)
self.btn.css_classes = ['temp']
self.btn.css_classes = []
def panel(self):
self.btn = pn.widgets.Button(name='Load', button_type='primary')
self.btn.js_on_click(
args={'btn': self.btn},
code='btn.css_classes.push("pn-loading", "arcs"); btn.properties.css_classes.change.emit();'
)
self.btn.on_click(lambda e: self.load())
return self.btn
d = Demo()
d.panel()

Fixed in #2467 but there is a wrinkle with your code, for some reason this doesn't work:
btn.css_classes.push("pn-loading", "arcs");
btn.properties.css_classes.change.emit()
but this does:
btn.css_classes = ["pn-loading", "arcs"]