Trigger FileInput() event

JavaScript newbie question here:

I’d like to allow the user to use a Dropdown widget to load a file. Rather than designing a custom widget, I figured an easy way to do this would be to have a hidden FileInput widget which gets “clicked” via a CustomJS callback when the user clicks the Dropdown widget. I can then use the FileInput widget as normal.

Unfortunately I can’t figure out how to trigger the “click” event on the FileInput widget in the CustomJS callback. Here’s what I tried:

from bokeh.io import curdoc
from bokeh.layouts import column
from bokeh.models import Dropdown, FileInput, CustomJS

# Set up widgets
dropdown = Dropdown(label='File', menu=['Open'])
fileinput = FileInput(visible=False)

# Set up callback for Dropdown widget
dropdown.js_on_click(CustomJS(args=dict(FileInput=fileinput),
    code="""
    if (this.item == 'Open')
        FileInput.click();
    """))

# Set up callback for hidden FileInput widget
def loadfile(attr, old, new):
    print(fileinput.filename)
fileinput.on_change('filename', loadfile)

# Set up layouts and add to document
curdoc().add_root(column(dropdown, fileinput))

The FileInput.click() code is not doing anything though…I just get an error in the console that FileInput.click is not a function.

Any tips?

I’ve realized that the FileInput variable in the JavaScript code above is the Bokeh model rather than the DOM element ID. If I open a web page showing a Bokeh document with a FileInput widget, right-click the widget and click “inspect”, that DOM element can be accessed as $0. So I can write in the Console: $0.click() and the FileInput widget is triggered.

So the question becomes how to get the DOM element ID of a widget created by Bokeh? It looks like widgets created by Bokeh don’t generally have DOM element IDs…when I select a widget and type in the console $0.id it just shows an empty string.

I see that one can get the Bokeh model name from JavaScript ([BokehJS] Add model selector · Issue #7147 · bokeh/bokeh · GitHub) using get_model_by_name()…any way to get the DOM element ID?

Bump? Still wondering.

One can get the DOM element ID via document.getElementById(), followed by querySelector('input[type=file]') if the element is embedded in the application’s Jinja template. Like so:

main.py:

from bokeh.io import curdoc
from bokeh.models import Dropdown, FileInput, CustomJS
from bokeh.events import ButtonClick

# Set up widgets
dropdown = Dropdown(label='File', menu=['Open'], name='Dropdown', tags=['hi'])
fileinput = FileInput(visible=False, name='FileInput')

# Set up callback for Dropdown widget
dropdown.js_on_click(CustomJS(code="""
    if (this.item == 'Open') {
        document.getElementById('FileInputElement').querySelector('input[type=file]').dispatchEvent(new MouseEvent('click'))
    }
    """))

# Set up callback for hidden FileInput widget
def loadfile(attr, old, new):
    print(fileinput.filename)
fileinput.on_change('filename', loadfile)

# Set up layouts and add to document
curdoc().add_root(dropdown)
curdoc().add_root(fileinput)

templates/index.html:

{% extends base %}

{% block contents%}
  <div>
    {{ embed(roots.Dropdown) }}
  </div>
  <div id="FileInputElement">
    {{ embed(roots.FileInput) }}
  </div>
{% endblock %}
1 Like

@efremdan1 thank you for circling back with the solution you found

1 Like

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.