Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Javascript errors when recreating widgets #22

Open
jeffyjefflabs opened this issue Jan 25, 2021 · 1 comment
Open

Javascript errors when recreating widgets #22

jeffyjefflabs opened this issue Jan 25, 2021 · 1 comment

Comments

@jeffyjefflabs
Copy link

jeffyjefflabs commented Jan 25, 2021

My organization was looking at using voila-material as our default template (love the kernel-busy indicator!), but we discovered it breaks a widget pattern we use for authentication. We have to upload a file and enter a password, so we have something like the below example, where uploading the file enables the password widget, while clicking the reset button recreates the upload widget and disables the password widget. Unfortunately, clicking reset generates javascript errors in the console and the password widget can no longer be enabled. This works fine in the default template.

upload = widgets.FileUpload()
reset = widgets.Button(description='reset')
password = widgets.Password(disabled=True)

def click_reset(b):
    password.disabled = True
    # recreate the FileUpload because there's no good way to reset it: ipywidgets#2653
    new_upload = widgets.FileUpload()
    new_upload.observe(upload_file)
    layout.children = [new_upload, reset, password]
    
def upload_file(c):
    password.disabled = False

reset.on_click(click_reset)
upload.observe(upload_file)
layout = widgets.VBox(children=[upload, reset, password])
layout

Here's a screenshot of the errors. It looks like this might be the same as #18 and #19?

image

Here's a slightly smaller example that generates the same errors:

widget = widgets.IntText()
button = widgets.Button(description='recreate')

def callback(b):
    new_widget = widgets.IntText()
    box.children = [new_widget, button]
    
button.on_click(callback)    
box = widgets.VBox(children=[widget, button])
box

Edited to add: voila 0.2.6 and voila-material 0.4.0

jeffyjefflabs added a commit to nbgallery/voila-nbgallery that referenced this issue Jan 26, 2021
@jeffyjefflabs
Copy link
Author

Javascript isn't really my thing and JupyterLab's kernel code even less so, but after poking around a bit today I think the problem is that there are two kernel connections (one from Voila itself and one from this template for the kernel-busy icon) and they're both trying to handle comm messages, but only one has the appropriate objects registered. There is code in @jupyterlab/services (originally from this PR) that allows a kernel connection to opt out of handling comms, and this code seems like it should automatically opt out. Then I realized that Voila is using an older version of @jupyterlab/services and doesn't even have that opt-out code. So, based on where handleComms is checked in kernel/default.ts, it looks like there are 5 functions that should be turned into no-ops, which led me to this workaround:

  <script type="text/javascript">
    requirejs(['static/voila'], function(voila) {
      (async function() {
        var kernel = await voila.connectKernel();

        // Don't try to handle comm messages
        kernel.registerCommTarget = () => {};
        kernel.removeCommTarget = () => {};
        kernel._handleCommOpen = () => {};
        kernel._handleCommClose = () => {};
        kernel._handleCommMsg = () => {};

        kernel.statusChanged.connect(() => {
          // console.log(kernel.status);
          var el = document.getElementById("kernel-status-icon");

          if (kernel.status == 'busy') {
            el.innerHTML = 'radio_button_checked';
          } else {
            el.innerHTML = 'radio_button_unchecked';
          }
        });
      })();
    });
  </script>

That seems to be working for my little examples above, but I'll plan on testing it with some of our full notebooks later.

It seems like the "real" fix might be for Voila to update to the latest @jupyterlab/services and make sure that the main Voila kernel connection is the only one trying to handle comm messages. But that's way outside my comfort zone. :-)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant