FileInput and CustomJS

What Are You Trying To do?

Set up a callback on a FileInput widget such that when the user loads a new file (csv but that’s not important for my problem really), the callback will also trigger the loading of another file based on some derivative of the original filename. For the MRE I post above, basically if they load “MYFILE.csv”, I want to also load “MYFILE_meta.csv”.

I want to use the content for both of them to do stuff.

My idea is:

  • Make two FileInputs (fi and meta_fi), only put fi into the layout, but pass both to the CustomJS.
  • CustomJS will trigger when the fi filename changes, i.e. user picks a file.
  • CustomJS parses the filename, adds _meta and then updates the filename of meta_fi to (hopefully) load that file.

But What Happens:

Changing the FileInput.filename does not trigger an update of the FileInput.value :frowning: so I can’t get my content from the second file.

What I’m searching for is a means of doing so.

What I’ve Tried:

See attached MRE and commentary in the CustomJS for ideas/straws I’ve grasped at.

I’ve looked at the source code as well → bokeh/file_input.ts at 404648077ba71339598936978db72b545d6f39fa · bokeh/bokeh · GitHub , and looked at lots of vanilla JS examples of FileInput but am totally lost as to how I might be able to leverage either.

MRE (you’ll have to make a dummy .csv file and load it in):


from bokeh.plotting import show, save
from bokeh.models import CustomJS, FileInput

fi = FileInput()

meta_fi = FileInput(tags=['meta'])


cb = CustomJS(args=dict(fi=fi,meta_fi=meta_fi)
              ,code='''
               console.log(fi.filename)
               console.log(fi.value)
               var meta_file = fi.filename.split('.csv')[0]+'_meta.csv'
               meta_fi.filename = meta_file
               meta_fi.change.emit()
               //see that the filename attribute updates but that doesn't trigger a reload of the value
               console.log(meta_fi.filename)
               console.log(meta_fi.value)
               
               //is there a way to trigger _read_file on meta_fi here to get the value property updated?
               console.log(meta_fi) //there doesn't seem to be much for to use inspecting this thing :-(
               //something like meta_fi.value.update() etc.??
               
               //i can also access it in the DOM with the tags part
               console.log(document.getElementsByTagName('meta')[0])
               // can i tell it somehow to load meta_file with dispatch event?!?!
               //... e.g. document.getElementsByTagName('meta')[0].dispatchEvent(new MouseEvent('click')) 
               ''')

                     
fi.js_on_change('filename',cb)

save(fi,'test.html')

… Thanks…

I wanted to do something similar to this, although in my case I had two filenames with the same basename but different suffixes. I didn’t try writing CustomJS of the sort that you have tried, but I eventually came to the conclusion (perhaps incorrect) that I couldn’t trigger the upload of a second file based upon the selection of the first.

What I ended up being able to do successfully was to leverage the multiple=True option to the FileInput widget to enable users to select multiple files within the FileInput chooser, which then both get uploaded to the server. (I should say that this is entirely within the context of running a Bokeh server, with Python callbacks triggered by actions on the FileInput widget.). In this case, I can create a FileInput button that accepts multiple files (in my case, with suffixes ‘.DTA’ and ‘.DSC’ that come in matched pairs), such as:

upload = FileInput(accept=‘.DTA,.DSC’, multiple=True)

This enables one to select multiple files within the chooser window (e.g., via Shift+Click). As a result, the filename and value attributes of the upload object are Python lists with multiple elements, which I can then process in an associated callback on the server. (Among other things, I check that only 2 files have been selected, and that they share the same basename, one for each suffix. In your case, you would presumably want to check that the two selected filenames differ by the ‘_meta’ string.)

If there is a way to trigger a second file upload from the first, as you have tried, that would be useful to know. In my case, I couldn’t figure out a way to do that, but I was happy to find an alternative solution. Perhaps this might work for you.

Best,
Chris

Thanks Chris, yeah I have basically gone the exact same route unless a solution/trick is found.

My hope was to avoid making the user upload multiple and just have the app look for an accompanying metadata file if it exists. Instead with multiple now I have to instruct users that they can select only a main file, or a main file and its _meta partner. Then when they upload 2, my CustomJS has to determine which is which, then do stuff with both.