I am writing a NodeJS Electron App to be distributed on all platforms. I have a download button that I would like to pop open a Save As dialog with the file being provided from the server. Does anybody know the best way to do this?
Here are the things I have tried that work when running the node app locally but fail after I have packaged the app with electron-packager:
- Setting window.location.href to the location of the file
- Setting the src of a hidden iframe to the location of the file
When running the packaged mac app, the "did-fail-load" event is fired and prevents the Save As dialog from showing. When looking at the network requests, I can see that the file is successfully retrieved from the server. I can't seem to figure out why the "did-fail-load" event is being fired.
Take a look at this page on the electron docs https://github.com/atom/electron/blob/master/docs/api/dialog.md
There is a section about dialog.showSaveDialog
Then you can use the URL from the save dialog with a function similar to the one below to save it to that location.
session.on('will-download', function(event, item, webContents) {
event.preventDefault();
require('request')(item.getUrl(), function(data) {
require('fs').writeFileSync('/somewhere', data);
});
});
Found on this page https://github.com/atom/electron/blob/master/docs/api/session.md
On the HTML button:
<button onclick='myUrlSaveAs("http://www.example.com/path/to/file.jpg")'>Save As</button>
In your javascript file:
// Include in the render side
var elerem = require('electron').remote;
var dialog = elerem.dialog;
var app = elerem.app;
var http = require('http');
var fs = require('fs');
var path = require('path');
function myUrlSaveAs(remoteUrl){
// app.getPath("desktop") // User's Desktop folder
// app.getPath("documents") // User's "My Documents" folder
// app.getPath("downloads") // User's Downloads folder
var toLocalPath = path.resolve(app.getPath("desktop"), path.basename(remoteUrl)
var userChosenPath = dialog.showSaveDialog({ defaultPath: toLocalPath });
if(userChosenPath){
download (remoteUrl, userChosenPath, myUrlSaveAsComplete)
}
}
function myUrlSaveAsComplete(err){
alert("done");
}
function download (url, dest, cb) {
var file = fs.createWriteStream(dest);
var request = http.get(url, function(response) {
response.pipe(file);
file.on('finish', function() {
file.close(cb); // close() is async, call cb after close completes.
});
}).on('error', function(err) { // Handle errors
fs.unlink(dest); // Delete the file async. (But we don't check the result)
if (cb) cb(err.message);
});
};