I’m trying to create a callback that produces a new tab that contains UI elements with their own callbacks. However, I’ve found that this seems to work fine for a Select widget but not for a Button widget in a dynamically created new tab.
With the following MWE, a single tab is automatically generated when the application starts. For this panel both the Select and Button callbacks work as expected. However, when a new tab is added by the user, the Select callback works for the new tab but the Button callback does not. I don’t understand why this is the case.
MWE
# app.py
from functools import partial
from bokeh.io import curdoc
import bokeh.models as bm
import bokeh.models.layouts as bl
i = 0
doc = curdoc()
def cb_selector(attr, old, new, div=None):
div.text = new
def cb_button(div=None):
div.text = ""
def cb_new_tab():
global i
i += 1
selector = bm.Select(value="", options=["foo", "bar", "baz"])
button = bm.Button(label="Reset")
div = bm.Div(text="Make selection")
layout = bl.Column(bl.Row(selector, button), div)
tab = bl.TabPanel(child=layout, title=f"Tab {i}")
tabs.tabs.append(tab)
# This callback works for tab 1 AND for new tabs
selector.on_change("value", partial(cb_selector, div=div))
# This callback works for tab 1, but NOT for new tabs
button.on_click(partial(cb_button, div=div))
add_tab_button = bm.Button(label="Add tab")
tabs = bl.Tabs(tabs=[])
add_tab_button.on_click(cb_new_tab)
cb_new_tab()
root_layout = bl.Column(add_tab_button, tabs)
doc.add_root(root_layout)
Start the app with bokeh serve --show app.py
Notice that changing the Select widget value in tab 1 changes the text in the Div widget in tab 1, as expected.
Notice that clicking the “Reset” Button in tab 1 resets the Div text in tab 1, as expected.
Create a new tab by clicking the “Add tab” Button.
Notice that changing the Select widget value in tab 2 changes the text in the Div widget in tab 2, as expected (and independent of tab 1).
Notice that clicking the “Reset” Button in tab 2 does not reset the Div text in tab 2. I don’t understand why this does not work as expected.