Dynamically adding pages

Hello again,

I would like to allow my users to add new pages at the click of a button. I know that I can have multiple pages by passing a dict to panel.serve as follows.

pn.serve(
    {"/app1": create_app1, "/app2": create_app2}
)

But can I somehow modify this object to add more pages? Or can I create a new dict and restart the server so it picks up the changes?

I was just having a random thought. Maybe the better approach would be to have a single application that, based on URL path, modifies what the user sees either by hiding elements or by modifying a stack of components. So kind of like a typical JS single page application.

1 Like

Hi @Midnighter

I don’t know of any way to dynamically add endpoints. But I have also had the question many times. Is it possible @philippjfr ?

Single Page App with multiple pages

If you want to create a SPA you can do something like this.

import panel as pn

pn.extension(sizing_mode="stretch_width", template="fast")

main = pn.Column().servable()

def home():
    return ["## Home", 1, 2]

def page1():
    return ["## Page 1", 2, 3]

def page2():
    return ["## Page 2", 4, 5]

PAGES = {
    "home": home, "page1": page1, "page2": page2
}

page_name = pn.widgets.RadioButtonGroup(name="Page", options=list(PAGES), orientation="vertical", button_type="success").servable(target="sidebar")

@pn.depends(page_name, watch=True)
def change_page(page_name):
    page_func = PAGES[page_name]
    main[:]=page_func()

change_page("home")

Use Session Args

What you can also do is for example to use pn.state.session_args to display a different page via query args.

import panel as pn

pn.extension(template="fast")

def home():
    pn.panel("Welcome. [Page 1](?page=page1) [Page2](?page=page2)").servable()

def page1():
    pn.panel("Page 1 [Home](?page=home)").servable()

def page2():
    pn.panel("Page 2 [Home](?page=home)").servable()

PAGES = {
    "home": home, "page1": page1, "page2": page2
}

def get_page_name():
    # {'page': [b'home']
    return pn.state.session_args.get("page", [b'home'])[0].decode(("utf8"))

page_name = get_page_name()
page_func = PAGES[page_name]
page_func()

1 Like

This is great, thank you for the examples. Looks like the most viable approach right now so I’ll go with this.

1 Like

Could you file a feature request about adding new routes dynamically? It should be technically possible by exposing the Tornado server and then using the add_handler method to define new routes.

2 Likes

Added Support adding new routes dynamically · Issue #4203 · holoviz/panel (github.com)

1 Like