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:
<!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>
app.js
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
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]);
}
};
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.
//It is possible when using Tampermonkey (Firefox or Chrome).
//They added the GM_Download command.
//You can use it like this download multiple files One time:
// ==UserScript==
// @name
// @description
// @match
// @grant
// @grant GM_download
function setup_reader(file) {
var name = file.name;
var reader = new FileReader();
reader.onload = function (e) {
var bin = e.target.result; //get file content
var lines = bin.split('\n');
for (var line = 0; line < lines.length; line++) {
console.log(lines[line]);
GM_download(lines[line], line + '.jpg');
}
}
// reader.readAsBinaryString(file);
reader.readAsText(file, 'utf-8');//
}
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 );
} );
Found the easiest way to do this. Works even with div!
<div onclick="downloadFiles()">
<!--do not put any text in <a>, it should be invisible-->
<a href="path/file1" id="a1" download></a>
<a href="path/file2" id="a2" download></a>
<a href="path/file3" id="a3" download></a>
<script>
function downloadFiles() {
document.getElementById("a1").click();
document.getElementById("a2").click();
document.getElementById("a3").click();
}
</script>
Download
</div>
That's all, hope it helps.