Hello guys,
I have a param.Action button created to trigger a run when it’s clicked. I’m wondering if there’s a way to check if the button is clicked ? kind of similar to ‘on_click’ event of button widget. Thanks!
Hi, Not sure what the use-case would be for checking the button click separately.
Basically for a Button you want to usually perform an action when the button is clicked. There are different ways to do it. But in essence you’re usually registering a function/method that gets called immediately when the button gets clicked.
Here an example with 3 different methods:
option 1 & 2 use the param.Parameterized + param.Action to allow automatically generate widgets and use param/panel convenience to link to the callback function/method.
option 3 is the classic defining a widget separately and linking a call-back function direclty.
The main difference between option 1 and option 2 is that with option 1 you can in theory have and trigger multiple dependencies, but in reality you likely need to actually trigger a sequence of steps in a specific order anyway, so use a single function to execute the work that needs to be done. Also you could still also trigger multiple dependencies on option 2, by adding a dependency to when the actual function gets executed (triggering more
import param
import panel as pn
pn.extension()
class Test(param.Parameterized):
# option 1: define an action that triggers itself.
# - you can use panel pn.Param or pn.widgets.Button.from_param() to create a Button automatically
# - once the button is hit the param.Parameterized class will execute anything
# that depends on that parameter via @param.depends or triggers any defined "watcher" for this parameter
abort = param.Action(default=lambda x: x.param.trigger('abort'))
# option 2: define an action that just directly calls the function/method
# - you can use panel pn.Param or pn.widgets.Button.from_param() to create a Button automatically
# - once the button is hit, the registered function/method will be directly executed
# (no extra @param.depends necessary)
save = param.Action(default=lambda self: self.save_data())
@param.depends('abort', watch=True)
def abort_change(self, **kwargs):
print(f'abort_change(self={self}, kwargs={kwargs})')
def save_data(self, **kwargs):
print(f'save_data(self={self}, kwargs={kwargs})')
# option 3: manually create a button widget and register a function via button.on_click()
# - you need to manually create the button, it will have *no* direct connection to the parameterized class
# - on button click the widget will call the registered callback function/method
def delete_button(self):
button = pn.widgets.Button(name='Delete')
button.on_click(self.delete_data)
return button
def delete_data(self, event, **kwargs):
print(f'delete_data(self={self}, event={event}, kwargs={kwargs})')
test = Test()
pn.Column(pn.Param(test.param), test.delete_button())
Not sure if that addresses your actual use-case or if you really need to do something very special.
Regards, Johann
Thanks for your reply. For my use case, the param.action is used to trigger a method to run a query and pull data from a database. So the subsequent steps depend on the data pull results. Widget button has the click event that I can use to track if the button is clicked so I can run the follow up process. However, param.action doesn’t have the click event. So I found this pn.state.param.busy Boolean value might seem to be useful for my use case. The only problem now is how to make the param.Action button click only one time so databse query only execute one time? Appreciate your help again!
Already wrapped up,traveling tomorrow. So just some thoughts.
To trigger any subsequent work externally after the button action is done you could try one of the 2 methods:
Store the action dB query result in a output param.parameter and put a @param.depends on it
2.put a @param.depends on the action callback method/function