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

Support adding files to <input type="file"> elements #749

Open
cigitia opened this Issue Oct 28, 2014 · 18 comments

Comments

Projects
None yet
@cigitia

cigitia commented Oct 28, 2014

It’s currently not possible to programmatically upload files using Electron. Electron should support adding local files to <input type="file"> elements.

Electron primarily uses file-path strings to read files: the purpose of both the dialog API and the File DOM object’s added API is to return file-path strings, which presumably will then be read by some node.js module.

It would be wonderful, however, if electron also somehow supported adding local files to <input type="file"> elements. For instance, a browser application that uses Electron may need to navigate to a webpage, then add a file chosen by the user to the webpage—without activating an OS-native file-choosing dialog. This might be because the application provides its own UI for choosing files, or it might be (as in my case) because the application’s purpose is to automate repetitive website forms that require the same files to be uploaded.

There are two ways I can think of doing this:

  1. Making it possible both to set the files properties of <input type="file"> elements to FileList objects (as NW.js does), to and construct FileList objects file-path strings (either arrays of strings, or File objects constructed from strings). This has the advantage of making it possible to directly reuse FileLists from drag and drop events, as well as other <input type="file"> elements. FileLists need not be mutable; the programmer could construct new ones every time they need them.

    [Edit: This is also the solution that NW.js has done.]

  2. Making it possible to set the files properties of <input type="file"> elements to arrays of file-path strings. (This has the advantage of using strings directly, which may be simpler in most cases.)

NW.js, the other node–Chromium project, already supports setting the files property of <input type="file"> elements, but that requires a preexisting FileList DOM object: it too does not support creating new FileLists. [Edit: This is actually incorrect. NW.js does also support creating new FileLists. See comment below.]

The Electron issue most related to this one is #454 (“Clicking on file input elements doesn't show file dialog”), but it is not the same, and this issue actually would determine whether I could use Electron for my own application.

In any case, Electron is amazing; cheers to all who have helped with it.

Related links:

@cigitia

This comment has been minimized.

cigitia commented Oct 28, 2014

Correction: though it’s otherwise undocumented, NW.js appears to already support both creating File objects from file-path strings and then adding them to FileLists. These in turn can be used to set the value of <input type="file"> elements’ files properties. Similar functionality in Electron would be very welcome.

@ghost

This comment has been minimized.

ghost commented Jun 21, 2015

Hello!
Has there been any progress on this issue since it was logged?

1 similar comment
@fritx

This comment has been minimized.

Contributor

fritx commented Sep 20, 2015

Hello!
Has there been any progress on this issue since it was logged?

@erikmellum

This comment has been minimized.

erikmellum commented Oct 6, 2015

This is a feature that would be incredibly useful. It's near impossible to programmatically upload a file in electron right now.

https://developer.mozilla.org/en-US/docs/Extensions/Using_the_DOM_File_API_in_chrome_code

I imagine it would like like this:

var file = File(dsFile.path);
and then I could do something like:
fd.append('attachment', file);
to build a form with a file without using the input dialog!

My app is for managing code projects, and you can push the code to an endpoint on the internet. I know where the file I need to upload is based on the path the files are stored, so why should I make them go through the extra step of selecting it for me?

More detail: http://stackoverflow.com/questions/8390855/how-to-instantiate-a-file-object-in-javascript

@lordgreg

This comment has been minimized.

lordgreg commented Nov 26, 2015

Has there been any news about this subject lately?

@kit92

This comment has been minimized.

kit92 commented Dec 23, 2015

Does anyone know where in the chromium blink JS engine I could find the handler for this? I would be willing to dive in the code and see if I could make the change to the methods to make this work. I'd just rather not have to read all the chromium code to find this one issue.

@svbatalov

This comment has been minimized.

svbatalov commented Apr 23, 2016

Hi.
We are making a browser automation tool (called The Bots Factory, or TBF) and one of our 'bots' required setting files in file input without user interaction. The trick that finally worked is to use chrome remote debugging, something like this:

// wv -- WebView
var wc = wv.getWebContents();
try {
  wc.debugger.attach("1.1");
} catch (err) {
  console.error("Debugger attach failed : ", err);
};

wc.debugger.sendCommand("DOM.getDocument", {}, function (err, res) {
  wc.debugger.sendCommand("DOM.querySelector", {
    nodeId: res.root.nodeId,
    selector: "#file"  // CSS selector of input[type=file] element
  }, function (err, res) {
    wc.debugger.sendCommand("DOM.setFileInputFiles", {
      nodeId: res.nodeId,
      files: ['/tmp/tst']  // Actual list of paths
    }, function (err, res) {
      wc.debugger.detach();
    });
  });
});

Note that the DevTools for the webview (in this case) must be closed for this to work.

Relevant pages:

@rosshinkley

This comment has been minimized.

rosshinkley commented Oct 4, 2016

@svbatalov's example works, but it appears that the MIME type determination based on the registry/XDG is skipped (it looks like include_platform_types might be false?). Some spot-checking leads me to believe that the hard coded MIME types will get determined properly, but anything else will fall to the default of application/octet-stream.

Is there a way to force the type check or explicitly set the type from the debugger?

@idododu

This comment has been minimized.

idododu commented Oct 18, 2016

+1

I am doing a upload app using electron and an opensource js upload library, and it works great in a webview.
I would like to add a feature: when open this app, it will continue to upload the file.
If I could set default files list for input file, then it will be easy to implement.

@idododu

This comment has been minimized.

idododu commented Oct 19, 2016

@svbatalov ,

  1. should I put your codes in main process or render process?
  2. do I have to use a webview tag in my html file?
@svbatalov

This comment has been minimized.

svbatalov commented Oct 19, 2016

AFAICT this approach should work as long as corresponding webContents is available (mind the DevTools restriction). Take a look at the following gist for simple demonstration (most of the code is identical to the above).

@idododu

This comment has been minimized.

idododu commented Oct 20, 2016

Tried your git, it works great!!!

detach debugger to avoid 'another debugger has been attached' error!

try {
        if(wc.debugger.isAttached()) {
            wc.debugger.detach();
        }
        wc.debugger.attach("1.1");
    } catch (err) {
        console.error("Debugger attach failed : ", err);
    }
@ios122

This comment has been minimized.

ios122 commented Jul 22, 2017

@ericbrumer

It's near impossible to programmatically upload a file in electron right now.

Maybe You hava find the way to do this,But I also want to share my idear.

Now, It is easy to programmatically upload a file in electron!!!

In your render process, you can get the Whole cookies include session cookies:

  const {session} = require('electron').remote

  session.defaultSession.cookies.get({
    url: window.location.href
  }, (error, cookies) => {
    console.log(error, cookies)
  })

And then you can programmatically upload a file with some nodejs library:

const request = require("request")

request({
  url: `http://www.example.com/api2/upload`,
  method:"POST",
  formData: {
    upload_type: "zip",
    file: fs.createReadStream(pathToAZip)
  },
  headers:{
    "cookie": cookie // a string,not a array.Looks like:  "i18next=zh-CN;appType=0;"
  }
},function (err, response, body) {
  console.log(err,response,body)
})
@WaiSiuKei

This comment has been minimized.

WaiSiuKei commented Dec 5, 2017

If there is node integration in the renderer process of your app, you can read the file as stream and then convert it to Blob.
Or maybe you can make it a function in the preload script for those without node integration(I haven't tried this one).

@samsamm777

This comment has been minimized.

samsamm777 commented Jan 16, 2018

Anything further on this? Im really struggling to get this working. I just need to create a File object from a path string.

@idododu

This comment has been minimized.

idododu commented Jan 26, 2018

@samsamm777 check svbatalov and my workaround above

@radreamer

This comment has been minimized.

radreamer commented Feb 8, 2018

Hi guys, i faced with the problem when trying to upload folder. I have the input:
<input type="file" webkitdirectory="true" onChange={e => { console.log(e.target.files) }} />
When i select folder with many files, i got FileList array with only one File instance – that directory, that i choose earlier. When i try it in the browser – all works as expected, e.g. http://jsfiddle.net/addyo/Ha979/

@jarry

This comment has been minimized.

jarry commented Jun 22, 2018

I have met same issues with @radarhere . I got the FileList that's length 1 in Electron when using <input directory>. In Chrome, I can get all files.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment