Widget Button to open url

Background: As apart of an application I do have links being displayed that one can click on to go to external pages (to the voila page), however in an attempt to make it a bit more presentable I wanted to see if I could just make some of the links into buttons.

I am attempting to create a widget button that will open a url.
This is run on a remote system (jupyterlab on a remote server) not local, as such using webbrowser.open will not work.

If I just run this on the remote system it works:

import ipywidgets as widgets
from IPython.display import display, Javascript

def window_open(url):
    display(Javascript(f'window.open("{url}");'))

window_open('https://www.google.com')

Then the new window opens fine.

When I wrap this in a button, it does not work:

import ipywidgets as widgets
from IPython.display import display, Javascript

def window_open_button(url):
    display(Javascript(f'window.open("{url.tooltip}");'))

ss = widgets.Button(description="hello", tooltip='https://www.google.com')
ss.on_click(window_open_button)
ss

When I click on the button, I ust get an entry in the jupyterlab log window saying:
<IPython.core.display.Javascript object>

image

I am not sure how to reason through why this is happening, any ideas of why and what a solution could be?

This is because the notebook does not know where to display the Javascript object, so instead it logs it in the console to let you know that something is amiss. One solution would be to point your display to a specific Output:

import ipywidgets as widgets
from IPython.display import display, Javascript

out = widgets.Output()


def window_open_button(url):
    with out:
        display(Javascript(f'window.open("{url.tooltip}");'))


ss = widgets.Button(description="hello", tooltip='https://www.google.com')
ss.on_click(window_open_button)

with out:
    display(ss)
out
3 Likes

Or, make a plain-old link look like a button, e.g. <a href="https://jupyter.org" target="_blank">hello</a> and use CSS to make it look like a button. For folks that already have middle-click-muscle-memory, this might even be more familiar.

3 Likes

Thank you for educating me on the reasons for that behavior and a solution that works.

This thread helped me to solve the same problem that @afonit had. Now I am trying to open several tabs with one click and I only get working the first one.
I copied the code of @krassowski and it works. then I added not one but two urls.

This code does not give any error but only opens the first URL:

import ipyvueetify as vue
from ipywidgets import Output
from IPython.display import Javascript

out2=Output()
b3 = vue.Btn(color='primary',children=['open tabs'])
def on_click3(widget, event, data):
    # generate an URL
    url_news   = "https://elpais.es"
    url_nyt    = "https://www.nytimes.com/"
    with out2:
        print('go')
        # VEEEEEEEERRRRY important: inside out
        display(Javascript(f'window.open("{url_nyt}");'))
        print('first')
    with out2:
        display(Javascript(f'window.open("{url_news}");'))
        print('second')
        
b3.on_event('click', on_click3)
display(b,out2)

When clicking the button the first url opens but not the second. (whatever is the second one), nevertheless “first” and “second” are printed out.

some idea why this happens? thanks

I am executing this same code from an external python file into the notebook using %run command. However, when I click on the button it does not open the url.

Manually, If I paste this code onto the code cell onto Jupyter Notebook it works fine!

Any fix to this issue?

I would expect it to not work with %run alone anyway. The reason being that with %run a script alone it runs as separate ‘instance’ itself and so once it finishes running, I believe it is gone (like running a shell command with ! in a notebook) and there’d be nothing to handle the code the button tries executing. That’s would be what I’d expect at least. But my limited understanding of the behind-the-scenes stuff may be lacking.

I was wondering if adding the -i option, see here to the run command to run it inside the notebook’s namespace might work; however, it didn’t. No matter what I try, I never see a button in either JupyterLab or classic notebook using krassowski’s November 21 code in an external file. I even tried the script as an .ipy script with and without the -i option for %run and never saw it.
What specifically are you running, how, and in what interface to even see a button from the external code?

Thanks for the reply.

Here I share some details about my approach:

  1. I make use of this command to execute a python file present in my Lab environment. And I encapsulate all the codes in the test_white_code.py script. This gives me the output along with the Submit score button on the notebook. @krassowski 's code

  1. This is another test button that I was asking for earlier. It works fine when I write the code within the notebook code cell. But I want to call this also from a script like in 1). For which I write the code inside my test_code_white.py file

But this does not show up. Maybe something I suspect something to do with the
out = widgets.Output() but not sure if I am missing anything here.

I can provide more details if needed.

1 Like