holoviz / panel

Panel: The powerful data exploration & web app framework for Python
https://panel.holoviz.org
BSD 3-Clause "New" or "Revised" License
4.71k stars 510 forks source link

Linking tab's "active" to a Parameter does not work as expected #7080

Closed samimia-swks closed 2 months ago

samimia-swks commented 2 months ago

[panel 1.4.4, python 3.11]

I am not quite sure this is supposed to work, but figured I'd report this. If it is not a bug I'd like to know the right way to do this.

I have a Parameterized class which holds the global states of my app. The app has two main tabs, and I would like to know which tab is active though my global state class. So I did something like this:  

import param

pn.extension()

class States(param.Parameterized):
    mode = param.Integer()

ss = States()

main_tabs = pn.Tabs(
    ("tab 0", pn.panel("tab 0 content")),
    ("tab 1", pn.panel("tab 1 content")),
    active=ss.param.mode,
).servable()

def this_works(active_tab):
    print(f"this_works: SWITCHED TO TAB {active_tab}")
pn.bind(this_works, main_tabs.param.active, watch=True)

def this_doesnt_work(active_tab):
    print(f"this_doesnt_work: SWITCHED TO TAB {active_tab}")
pn.bind(this_doesnt_work, ss.param.mode, watch=True)

From reading this doc I would expect both this_works() and this_doesnt_work() to trigger when I switch tabs, but only this_works() does. Is this expected?

philippjfr commented 2 months ago

Thanks for the issue. To answer your question, parameter binding like you're doing is not bi-directional, i.e.

main_tabs = pn.Tabs(
    ("tab 0", pn.panel("tab 0 content")),
    ("tab 1", pn.panel("tab 1 content")),
    active=ss.param.mode,
).servable()

binds the value of mode on the ss instance to the active parameter but does not do the reverse. If you need the bi-directional linking you can do this instead:

main_tabs = pn.Tabs(
    ("tab 0", pn.panel("tab 0 content")),
    ("tab 1", pn.panel("tab 1 content")),
).servable()

main_tabs.link(ss, active='mode', bidirectional=True)