Help with synchronizing Card widgets

Hey all!
Long time lurker, first time poster. I’ve been using Panel for about a year now to build internal webapps for my team and loving it.

I’m curious if I stumbled on a bug, or I’m missing something obvious. My goal is to synchronize the ‘collapsed’ state across multiple Card widgets. I’d like to have one Card collapsible, and the rest of the Cards to follow its state. Using the below example, it doesn’t work:

My minimal reproducible example:

import param
import panel as pn

class MonitorGroup(param.Parameterized):
    group_toggle = pn.Card(title='toggle',
                                objects=['cat1', 'cat2', 'cat3'],
                                collapsed=True)
    # group_toggle =  pn.widgets.Toggle(name='Toggle', button_type='success')
    catagories = [pn.Card(title='✅',
                               objects=[f'## asdf {i}'],
                               collapsible=False,
                               collapsed=True) for i in range(3)]

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

    # Fails with: AttributeError: 'bool' object has no attribute 'param'
    # @param.depends('group_toggle.collapsed.value', watch=True)
    # Doesn't trigger on_toggle when Card collapsed/uncollapsed
    @param.depends('group_toggle.collapsed', watch=True)
    # Doesn't trigger on_toggle when Card collapsed/uncollapsed
    # @pn.depends('group_toggle.collapsed', watch=True)
    def on_toggle(self):
        print('on_toggle')
        for card in self.catagories:
            # card.collapsed = not self.group_toggle.value
            card.collapsed = not self.group_toggle.collapsed.value

    def view(self):
        return pn.Row(self.group_toggle, *self.catagories)

mg = MonitorGroup()
mg.view().show()

I can’t seem to figure out how to trigger on_toggle() when the Card gets collapsed/uncollapsed. I managed to achieve the same behavior with a pn.widgets.Toggle, but would really like to figure out why my approach fails with a Card.

Thanks,
Leo

Hi @leogolds

Congrats on your first post. Hope to see you posting more soon :+1:

Try changing

card.collapsed = not self.group_toggle.collapsed.value

to

card.collapsed = not self.group_toggle.collapsed.

At least that would give you the below.

import param
import panel as pn

class MonitorGroup(param.Parameterized):
    group_toggle = pn.Card(title='toggle',
                                objects=['cat1', 'cat2', 'cat3'],
                                collapsed=True)
    # group_toggle =  pn.widgets.Toggle(name='Toggle', button_type='success')
    catagories = [pn.Card(title='✅',
                               objects=[f'## asdf {i}'],
                               collapsible=False,
                               collapsed=True) for i in range(3)]

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

    # Fails with: AttributeError: 'bool' object has no attribute 'param'
    # @param.depends('group_toggle.collapsed.value', watch=True)
    # Doesn't trigger on_toggle when Card collapsed/uncollapsed
    @param.depends('group_toggle.collapsed', watch=True)
    # Doesn't trigger on_toggle when Card collapsed/uncollapsed
    # @pn.depends('group_toggle.collapsed', watch=True)
    def on_toggle(self):
        print('on_toggle')
        for card in self.catagories:
            # card.collapsed = not self.group_toggle.value
            card.collapsed = not self.group_toggle.collapsed

    def view(self):
        return pn.Row(self.group_toggle, *self.catagories)

mg = MonitorGroup()
mg.view().servable()

Thanks for the quick reply!
My issue is actually with on_toggle() not triggering, not the specific logic inside the function. I tried your solution in a notebook and as a standalone app using .show(), and getting the same behavior:

p.s. seems like I’m still on panel 0.10.1, which might be the cause of my issue. Will try to update to the latest and retry

After updating panel from 0.10.1 → 0.11.3 (which also pulled in a new version of bokeh), my original example works.
Thanks Marc for helping out!

1 Like