How to make a dynamic link in panel

So I have an app that only after it loads is it able to generate the correct hyperlink for one of the buttons. It has to wait til after it loads (or in the way I’m trying to do it until a user clicks on the button) to generate the link to send the user to (a different page). I’m not sure how to do this with jscallback or js_on_click. Here’s where I’m at so far:

    def update(event, save=True): 
        if pn.state.location:
            passed_args = args.search_kwargs_to_dict(pn.state.location.search)
            user_id = passed_args.get('user_id', 0)
        dbc = database.get_connection()
        df = dbc.get('selections', values={'user_id': user_id}, pandas=True)
        df = df.sort_values(by='created',ascending=False)
        url = df.iloc[0]['url']
        button.js_on_click(args={'target': url}, code='window.open(target.value)')
    
    button = pn.widgets.Button(name='load selections')
    button.on_click(update)

So this is pretty wonky. I’m adding the js_on_click inside the callback function, and that doesn’t even work, from what I can see. but I am able to generate the correct URL to send the user to in the callback function - the part I’m struggling with is, how do I actually then send them to that URL?

Any help would be greatly appreciated!

Hi @lastmeta,

If I get you right, you want to open a link-url that you do not know when you create the button, correct?
(I had the same issue.)

If so, in my understanding of the panel framework, you have to recreate the button, if you want to change the callback as the callback js code is part of the generated html page.

Replace the button with a placeholder. placeholder = pn.Row("") that you add to the dashboard.

If you change the link, recreate the button with the new url. button = pn.widgets.Button(name='load selections')

Add the callback button.js_on_click(args={'target': url}, code='window.open(target.value)')

And then place the button inside placeholder[:] = [button]

In you scenario, you might also have to re-add the on_click function.

2 Likes

Hi @rbps1

A working example could be something like this.

import panel as pn

pn.config.sizing_mode = "stretch_width"


search_text_area = pn.widgets.TextInput(placeholder="Enter Search")
search_button = pn.widgets.Button(name="Search", sizing_mode="fixed")
js_panel = pn.pane.HTML(width=0, height=0, margin=0, sizing_mode="fixed")
search_component = pn.Row(search_text_area, search_button, js_panel)


def execute_javascript(script):
    script = f'<script type="text/javascript">{script}</script>'
    js_panel.object = script
    js_panel.object = ""


def open_panel_search(event):
    search = search_text_area.value
    href = f"https://panel.holoviz.org/search.html?q={search}"

    # c.f. https://www.w3schools.com/jsref/met_win_open.asp
    script = f"window.open('{href}', '_blank')"
    execute_javascript(script)


search_button.on_click(open_panel_search)

template = pn.template.FastListTemplate(
    title="Panel Search",
    main=[search_component]
).servable()
2 Likes

@Marc strikes again! I’ve seen and learned from so many of your examples on here, amazing stuff thanks!

1 Like