
I am wondering how you can have a hybrid callback that allows to run both Python and JS code (i.e. when a button is clicked). Essentially I’d like to execute a CustomJS first, then run some Python code and finally execute another CustomJS callback.

I am wondering how you can have a hybrid callback that allows to run both Python and JS code (i.e. when a button is clicked). Essentially I’d like to execute a CustomJS first, then run some Python code and finally execute another CustomJS callback.

There is no way to ensure ordering of JS / Python callbacks on the same property. In practice, a JS callback would almost certainly execute first, since it is “right there”. But if you really want to ensure ordered, I think you would have to:
This seems failely clunky but I can’t think of another alternative.

I had something similar in mind but hoped a more elegant solution exists.
Out of curiousity why is not possible to execute a CustomJS directly without binding it to a property?
You can invoke a callback which runs CustomJS code on events other than model-property change events. In your first example, you can use an on-click event when a button is pressed.
There are a couple ways to do this that are syntactically different but functionally the same.
See the Adding Widgets section of the documentation for a button.js_on_click() example.
See the Events documentation for the syntax using the more general js_on_event() syntax.
For completeness, other types of user-interaction events such as manipulating or navigating plots also exist.

An event is still not a direct trigger/execution, in other words I’d like to do something like the following: CustomJS(…).execute() without any property/event/etc. binding which is apparently not possible as far as I know.

@Maxxner There’s nothing stopping you from calling execute but you would have to supply some dummy value for cb_obj.
why is not possible to execute a CustomJS directly without binding it to a property?
Same answer as always: that’s just the history of how things were developed in response to requirements at the time. FWIW very few people have ever asked about this, so naturally it has not gotten much thought or attention.

I wanted the same issue solved and I have my solution similar to Bryan’s.
def register_latent_event(self, py_handler, py_args:dict={}) -> Div:
def newfunc(attr, old, new):
return py_handler(attr=attr, old=old, new=new, **py_args)
py_obj = Div(visible=False)
py_obj.on_change('text', newfunc)
self.add(py_obj, self.name + '_handler_' + py_handler.__name__) # Add it to doc and post it to the template
self.latent_handlers.append(py_obj.name)
return py_obj
def js_call_python_after_js(self, py_handler, py_args:dict={}, js_code:str='', js_args:dict={}) -> CustomJS:
py_obj = self.register_latent_event(py_handler, py_args)
js_args.update(dict(py_handler=py_obj, py_args=py_args))
js_handler = CustomJS(args=js_args, code=js_code)
return js_handler

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.
End of archived discussion · Replies are disabled