How to use param.watch on param.Action?

I want a button defined in class A to call a method of class B.

When I define a button directly as pn.widgets.Button, I get it running with the param.watch method.
However, when I create the button from a param.Action mapping, I can’t manage to get the watcher going.

In the example below both buttons are created, but only the panel direct button calls B.compute()

Any tips on how to add a watcher of a.action in b?

import param
import panel as pn


class A(param.Parameterized):

    action = param.Action(lambda x: print("action"), label="param mapped")

    def __init__(self, **params):
        super().__init__(**params)
        self.button = pn.widgets.Button(name="panel direct")

    def view(self):
        return self.button


class B(param.Parameterized):

    def __init__(self, a, **params):
        super().__init__(**params)
        a.param.watch(self.compute, 'action', what='clicks', onlychanged=False)
        a.button.param.watch(self.compute, 'clicks')

    def compute(self, event):
        print(event)


a = A()
b = B(a)

pn.serve(pn.Column(a.param, a.view), show=False)

Hi @Leonidas

Would something like below work for you?

click
compute
import param
import panel as pn


class A(param.Parameterized):

    action = param.Action(label="param mapped")
    clicks = param.Integer()

    def __init__(self, **params):
        super().__init__(**params)

        self.action = self._click

    def view(self):
        return pn.Param(self.param.action)[0]

    def _click(self, *events):
        print("click")
        self.clicks += 1

class B(param.Parameterized):
    a = param.ClassSelector(class_=A)

    def __init__(self, **params):
        super().__init__(**params)

        self.a.param.watch(self.compute, 'clicks', onlychanged=False)

    def compute(self,*events):
        print("compute")

a = A()
b = B(a=a)

pn.Column(a.view).servable()

I think the problem is that the Action does not raise any events when clicked. I have seen some development on Github on this. And I think it’s coming soon. But I don’t know for sure.

1 Like

In recent versions of param you also have param.Event which is a boolean which temporarily switches to True when an event is triggered:

import param
import panel as pn

class A(param.Parameterized):

    action = param.Event(label="param mapped")

class B(param.Parameterized):

    def __init__(self, a, **params):
        super().__init__(**params)
        a.param.watch(self.compute, 'action')

    def compute(self, event):
        print(event)

a = A()
b = B(a)

pn.serve(pn.Column(a.param), show=True)
1 Like

I wasn’t aware of param.Event(). It is exactly what I was looking for! thnx @philippjfr !

@Marc Thanks for cooking up a work-around. It seems that with param.Event there isn’t even a need for a work-around, but thanks for the effort anyway!

1 Like