Template.main.append does not work!

The following code dynamically reads Python files from the pages module. Each file contains a create_page function, which returns objects like pn.Column that can be rendered in Panel.

My design is to dynamically read each Python file, create one button for each file in the sidebar, and, upon clicking a button, replace the content of the main area with the content returned by the corresponding create_page function.

import panel as pn
import pkgutil
import importlib

pages = dict()
for _, page, _ in pkgutil.iter_modules(["pages"]):
    pages[page] = importlib.import_module(f"pages.{page}")

template = pn.template.FastListTemplate(
    title="Muti pages demo",
    site="Web main"
)


def change_main_content(event):
    template.main.clear()
    template.main.append(pages[event.obj.name].create_page())


def change_main_content_str(event):
    print(event)
    template.main.clear()
    template.main.append(pages[event].create_page())


for page in pages.keys():
    page_button = pn.widgets.Button(name=page)
    # Issue: Clicking the button to trigger the change_main_content_str function 
    # does not update the main area!
    page_button.on_click(lambda event: change_main_content_str(event.obj.name))
    # However, calling the function directly works as expected!
    change_main_content_str("data")
    template.sidebar.append(page_button)


template.servable()

Why does this issue occur? How can it be fixed?

To get around this, wrap a column inside:
main=[pn.Column()]

template.main[0].append()

1 Like

Thank you so much. You fixed it! But I’d like to know why the original method didn’t work. Could you please explain the reason?

Something to do with the fact that the templates are jinja2 HTML template files. In the soon future, we will be migrating off that, and you can build templates with native Panel components, and you won’t have to work around it like this.

1 Like