Reputation: 12205
So I have a httpd server running which has links to a bunch of files. Lets say the user selects three files from a file list to download and they're located at:
mysite.com/file1
mysite.com/file2
mysite.com/file3
When they click the download button I want them to download these three files from the links above.
My download button looks something like:
var downloadButton = new Ext.Button({
text: "Download",
handler: function(){
//download the three files here
}
});
Upvotes: 70
Views: 235922
Reputation: 45
The native JavaScript solution could be something like this:
document.getElementById("download-example-csv-files").onclick = function(event) {
event.preventDefault()
document.getElementById("download-example-csv-example").click()
setTimeout(() => document.getElementById("download-example-csv-database").click(), 2500)
};
<p>
<a id="download-example-csv-example" style="display: none;" href="{% static 'giftplanner–csv-example-files/Buddy_Butler_Copy-Paste-Vorlage.csv' %}"></a>
<a id="download-example-csv-database" style="display: none;" href="{% static 'giftplanner–csv-example-files/Buddy_Butler_Muster-Datenbank.csv' %}"></a>
<a id="download-example-csv-files" href="#">Muster-CSV Download</a>
</p>
The href I added with Django syntax. Could be common URLs of course.
Upvotes: 0
Reputation: 9949
You can either:
Note: Option one is objectively better.
And an option three: Download multiple files with a single action
Upvotes: 5
Reputation: 21
This is the easiest way I have found to download multiple files.
$('body').on('click','.download_btn',function(){
downloadFiles([
['File1.pdf', 'File1-link-here'],
['File2.pdf', 'File2-link-here'],
['File3.pdf', 'File3-link-here'],
['File4.pdf', 'File4-link-here']
]);
})
function downloadFiles(files){
if(files.length == 0){
return;
}
file = files.pop();
var Link = $('body').append('<a href="'+file[1]+'" download="file[0]"></a>');
Link[0].click();
Link.remove();
downloadFiles(files);
}
This should work for you.
Upvotes: 1
Reputation: 230
Use:
<!DOCTYPE html>
<html ng-app='app'>
<head>
<title>
</title>
<link rel="stylesheet" href="http://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css">
<link rel="stylesheet" href="style.css">
</head>
<body ng-cloack>
<div class="container" ng-controller='FirstCtrl'>
<table class="table table-bordered table-downloads">
<thead>
<tr>
<th>Select</th>
<th>File name</th>
<th>Downloads</th>
</tr>
</thead>
<tbody>
<tr ng-repeat = 'tableData in tableDatas'>
<td>
<div class="checkbox">
<input type="checkbox" name="{{tableData.name}}" id="{{tableData.name}}" value="{{tableData.name}}" ng-model= 'tableData.checked' ng-change="selected()">
</div>
</td>
<td>{{tableData.fileName}}</td>
<td>
<a target="_self" id="download-{{tableData.name}}" ng-href="{{tableData.filePath}}" class="btn btn-success pull-right downloadable" download>download</a>
</td>
</tr>
</tbody>
</table>
<a class="btn btn-success pull-right" ng-click='downloadAll()'>download selected</a>
<p>{{selectedone}}</p>
</div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.0/jquery.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular.min.js"></script>
<script src="script.js"></script>
</body>
</html>
var app = angular.module('app', []);
app.controller('FirstCtrl', ['$scope','$http', '$filter', function($scope, $http, $filter){
$scope.tableDatas = [
{name: 'value1', fileName:'file1', filePath: 'data/file1.txt', selected: true},
{name: 'value2', fileName:'file2', filePath: 'data/file2.txt', selected: true},
{name: 'value3', fileName:'file3', filePath: 'data/file3.txt', selected: false},
{name: 'value4', fileName:'file4', filePath: 'data/file4.txt', selected: true},
{name: 'value5', fileName:'file5', filePath: 'data/file5.txt', selected: true},
{name: 'value6', fileName:'file6', filePath: 'data/file6.txt', selected: false},
];
$scope.application = [];
$scope.selected = function() {
$scope.application = $filter('filter')($scope.tableDatas, {
checked: true
});
}
$scope.downloadAll = function(){
$scope.selectedone = [];
angular.forEach($scope.application,function(val){
$scope.selectedone.push(val.name);
$scope.id = val.name;
angular.element('#'+val.name).closest('tr').find('.downloadable')[0].click();
});
}
}]);
Plunker example: https://plnkr.co/edit/XynXRS7c742JPfCA3IpE?p=preview
Upvotes: 1
Reputation: 600
You could go for the iframe
.
Note: though this is one of the few ways to download multiple files at once, without creating pop-up, this won't work with files that can be rendered in browser. Check the JavaScript code comments.
Note 2: some browsers may ask for permission to download multiple files from the same page
function download(){
const links = ["mysite.com/file1", "mysite.com/file2", "mysite.com/file3"]
// It only works with files that don't render in the browser
// I.e., not video, not text, not and photo
for(let i = 0; i < links.length; i++) {
var frame = document.createElement("iframe");
frame.src = links[i];
frame["download"] = 1
document.body.appendChild(frame);
}
}
iframe{
display: none;
}
<body>
<div onclick="download()">Download</div>
</body>
Upvotes: 2
Reputation: 67
This solution works perfectly fine for me:
var downloadButton = new Ext.Button({
text: "Download",
handler: function () {
/** @type {Array<string>} URLS */
const URLS = [
"mysite.com/file1 ",
"mysite.com/file2",
"mysite.com/file3",
];
for (let x = 0; x < URLS.length; x++) {
/** @type {string} URL */
const URL = URLS[x];
/** @type {HTMLLinkElement} LINK */
const LINK = document.createElement('a');
LINK.href = URL;
LINK.setAttribute('download', 'download');
document.body.appendChild(LINK);
LINK.click();
LINK.parentNode.removeChild(LINK);
window.URL.revokeObjectURL(URL);
}
}
});
Upvotes: 0
Reputation: 2275
Another possibility is using the downloads.download()
API. Which is however not supported by Safari.
await Promise.all(
browser.downloads.download({url : downloadUrl1}),
browser.downloads.download({url : downloadUrl2})
);
Upvotes: -1
Reputation: 281
downloadAll(links) {
const urls = links;
for (let link of urls) {
window.open(link, '_blank');
}
}
This code defines a downloadAll function that takes an array of links as a parameter. It then iterates over each link and opens it in a new browser tab using window.open(link, '_blank'). This will trigger the file download for each link.
However, please note that to successfully download files using this method, the user's browser settings must allow pop-up windows. If pop-up blocking is enabled, the files may not be downloaded as intended.
Keep in mind that this solution relies on the browser's default behavior for opening new tabs and triggering file downloads. Different browsers may handle this differently, and there's no guarantee that all files will be downloaded simultaneously. It's also worth noting that if you're trying to download a large number of files, it may cause performance issues or exceed browser limitations.
Upvotes: 0
Reputation: 13640
I fond that executing click()
event on a
element inside a for loop
for multiple files download works only for limited number of files (10 files in my case). The only reason that would explain this behavior that made sense to me, was speed/intervals of downloads executed by click()
events.
I figure out that, if I slow down execution of click()
event, then I will be able to downloads all files.
This is solution that worked for me.
var urls = [
'http://example.com/file1',
'http://example.com/file2',
'http://example.com/file3'
]
var interval = setInterval(download, 300, urls);
function download(urls) {
var url = urls.pop();
var a = document.createElement("a");
a.setAttribute('href', url);
a.setAttribute('download', '');
a.setAttribute('target', '_blank');
a.click();
if (urls.length == 0) {
clearInterval(interval);
}
}
I execute download event click()
every 300ms. When there is no more files to download urls.length == 0
then, I execute clearInterval
on interval
function to stop downloads.
Upvotes: 32
Reputation: 198
This works in all browsers (IE11, Firefox, Microsoft Edge, Chrome and Chrome Mobile) My documents are in multiple select elements. The browsers seem to have issues when you try to do it too fast... So I used a timeout.
<select class="document">
<option val="word.docx">some word document</option>
</select>
//user clicks a download button to download all selected documents
$('#downloadDocumentsButton').click(function () {
var interval = 1000;
//select elements have class name of "document"
$('.document').each(function (index, element) {
var doc = $(element).val();
if (doc) {
setTimeout(function () {
window.location = doc;
}, interval * (index + 1));
}
});
});
This solution uses promises:
function downloadDocs(docs) {
docs[0].then(function (result) {
if (result.web) {
window.open(result.doc);
}
else {
window.location = result.doc;
}
if (docs.length > 1) {
setTimeout(function () { return downloadDocs(docs.slice(1)); }, 2000);
}
});
}
$('#downloadDocumentsButton').click(function () {
var files = [];
$('.document').each(function (index, element) {
var doc = $(element).val();
var ext = doc.split('.')[doc.split('.').length - 1];
if (doc && $.inArray(ext, docTypes) > -1) {
files.unshift(Promise.resolve({ doc: doc, web: false }));
}
else if (doc && ($.inArray(ext, webTypes) > -1 || ext.includes('?'))) {
files.push(Promise.resolve({ doc: doc, web: true }));
}
});
downloadDocs(files);
});
Upvotes: 2
Reputation: 2085
I've solved this a different way by using window.location. It works in Chrome, which fortunately is the only browser I had to support. Might be useful to someone. I'd initally used Dan's answer, which also needed the timeout I've used here or it only downloaded one file.
var linkArray = [];
linkArray.push("http://example.com/downloadablefile1");
linkArray.push("http://example.com/downloadablefile2");
linkArray.push("http://example.com/downloadablefile3");
function (linkArray) {
for (var i = 0; i < linkArray.length; i++) {
setTimeout(function (path) { window.location = path; }, 200 + i * 200, linkArray[i]);
}
};
Upvotes: 4
Reputation: 1571
This was the method which worked best for me and didn't open up new tabs, but just downloaded the files/images I required:
var filesForDownload = [];
filesForDownload( { path: "/path/file1.txt", name: "file1.txt" } );
filesForDownload( { path: "/path/file2.jpg", name: "file2.jpg" } );
filesForDownload( { path: "/path/file3.png", name: "file3.png" } );
filesForDownload( { path: "/path/file4.txt", name: "file4.txt" } );
$jq('input.downloadAll').click( function( e )
{
e.preventDefault();
var temporaryDownloadLink = document.createElement("a");
temporaryDownloadLink.style.display = 'none';
document.body.appendChild( temporaryDownloadLink );
for( var n = 0; n < filesForDownload.length; n++ )
{
var download = filesForDownload[n];
temporaryDownloadLink.setAttribute( 'href', download.path );
temporaryDownloadLink.setAttribute( 'download', download.name );
temporaryDownloadLink.click();
}
document.body.removeChild( temporaryDownloadLink );
} );
Upvotes: 32
Reputation: 749
The best way to do this is to have your files zipped and link to that:
The other solution can be found here: How to make a link open multiple pages when clicked
Which states the following:
HTML:
<a href="#" class="yourlink">Download</a>
JS:
$('a.yourlink').click(function(e) {
e.preventDefault();
window.open('mysite.com/file1');
window.open('mysite.com/file2');
window.open('mysite.com/file3');
});
Having said this, I would still go with zipping the file, as this implementation requires JavaScript and can also sometimes be blocked as popups.
Upvotes: 44