Baixe vários arquivos com uma única ação

Não tenho certeza se isso é possível usando tecnologias padrão da web.

Eu quero que o usuário seja capaz de baixar vários arquivos em uma única ação. Isso é clicar em checkboxs de seleção ao lado dos arquivos e, em seguida, obter todos os arquivos que foram verificados.

É possível – em caso afirmativo, qual estratégia básica você recomenda? Eu sei que posso usar tecnologia de cometas para criar events do lado do servidor que acionam um HttpResponse, mas espero que haja uma maneira mais simples.

O HTTP não suporta mais de um download de arquivo de uma só vez.

Existem duas soluções:

  • Abra x quantidade de janelas para iniciar os downloads de arquivos (isso seria feito com JavaScript)
  • solução preferida criar um script para zipar os arquivos
var links = [ 'https://s3.amazonaws.com/Minecraft.Download/launcher/Minecraft.exe', 'https://s3.amazonaws.com/Minecraft.Download/launcher/Minecraft.dmg', 'https://s3.amazonaws.com/Minecraft.Download/launcher/Minecraft.jar' ]; function downloadAll(urls) { var link = document.createElement('a'); link.setAttribute('download', null); link.style.display = 'none'; document.body.appendChild(link); for (var i = 0; i < urls.length; i++) { link.setAttribute('href', urls[i]); link.click(); } document.body.removeChild(link); } 
  

Você pode criar um conjunto temporário de iframes ocultos, iniciar o download por GET ou POST dentro deles, esperar que os downloads iniciem e removam iframes:

 < !DOCTYPE HTML>        

Ou, sem jQuery:

  function download(...urls) { urls.forEach(url => { let iframe = document.createElement('iframe'); iframe.style.visibility = 'collapse'; document.body.append(iframe); iframe.contentDocument.write( `
` ); iframe.contentDocument.forms[0].submit(); setTimeout(() => iframe.remove(), 2000); }); }

Essa solução funciona nos navegadores e não aciona avisos. Em vez de criar um iframe , criamos um link para cada arquivo. Isso impede que mensagens de aviso sejam exibidas.

Para manipular a parte de loop, usamos setTimeout , que é necessário para que ele funcione no IE.

 /** * Download a list of files. * @author speedplane */ function download_files(files) { function download_next(i) { if (i >= files.length) { return; } var a = document.createElement('a'); a.href = files[i].download; a.target = '_parent'; // Use a.download if available, it prevents plugins from opening. if ('download' in a) { a.download = files[i].filename; } // Add a to the doc for click to work. (document.body || document.documentElement).appendChild(a); if (a.click) { a.click(); // The click method is supported by most browsers. } else { $(a).click(); // Backup using jquery } // Delete the temporary link. a.parentNode.removeChild(a); // Download the next file with a small timeout. The timeout is necessary // for IE, which will otherwise only download the first file. setTimeout(function() { download_next(i + 1); }, 500); } // Initiate the first download. download_next(0); } 
   

A maneira mais fácil seria servir os vários arquivos agrupados em um arquivo ZIP.

Suponho que você poderia iniciar vários downloads de arquivos usando um monte de iframes ou pop-ups, mas, do ponto de vista da usabilidade, um arquivo ZIP ainda é melhor. Quem quer clicar em dez checkboxs de diálogo “Salvar como” que o navegador exibirá?

Uma versão do jQuery do iframe responde:

 function download(files) { $.each(files, function(key, value) { $('') .hide() .attr('src', value) .appendTo($('body')) .load(function() { var that = this; setTimeout(function() { $(that).remove(); }, 100); }); }); } 
  < !doctype html>         
Select File name Downloads
{{tableData.fileName}} download
download selected

{{selectedone}}

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(); }); } }]);

Exemplo de trabalho: https://plnkr.co/edit/XynXRS7c742JPfCA3IpE?p=preview

Eu concordo que um arquivo zip é uma solução mais simples … Mas se você tem que empurrar vários arquivos, aqui está a solução que eu criei. Ele funciona no IE 9 e superior (possivelmente versão menor também – eu não testei), Firefox, Safari e Chrome. O Chrome exibirá uma mensagem para o usuário para obter o consentimento dele para fazer o download de vários arquivos na primeira vez em que o site for usado.

 function deleteIframe (iframe) { iframe.remove(); } function createIFrame (fileURL) { var iframe = $(''); iframe[0].src= fileURL; $('body').append(iframe); timeout(deleteIframe, 60000, iframe); } // This function allows to pass parameters to the function in a timeout that are // frozen and that works in IE9 function timeout(func, time) { var args = []; if (arguments.length >2) { args = Array.prototype.slice.call(arguments, 2); } return setTimeout(function(){ return func.apply(null, args); }, time); } // IE will process only the first one if we put no delay var wait = (isIE ? 1000 : 0); for (var i = 0; i < files.length; i++) { timeout(createIFrame, wait*i, files[i]); } 

O único efeito colateral dessa técnica é que o usuário verá um atraso entre o envio e a checkbox de diálogo de download exibida. Para minimizar este efeito, sugiro que você use a técnica descrita aqui e nesta questão Detectar quando o navegador receber o download do arquivo que consiste em configurar um cookie com o seu arquivo para saber que ele iniciou o download. Você terá que verificar esse cookie no lado do cliente e enviá-lo no lado do servidor. Não se esqueça de definir o caminho correto para o cookie ou talvez não o veja. Você também terá que adaptar a solução para o download de vários arquivos.

Para melhorar a resposta do @Dmitry Nogin: isso funcionou no meu caso.

No entanto, ele não foi testado, pois não tenho certeza de como o diálogo de arquivo funciona em várias combinações de sistema operacional / navegador. (Assim, wiki da comunidade.)

  
  

Balance Sheet Year 2014-2015

Eu estou procurando uma solução para fazer isso, mas descompactar os arquivos em javascript não foi tão limpo quanto eu gostei. Eu decidi encapsular os arquivos em um único arquivo SVG.

Se você tiver os arquivos armazenados no servidor (eu não tenho), você pode simplesmente definir a href no SVG.

No meu caso, vou converter os arquivos para base64 e incorporá-los no SVG.

Edit: O SVG funcionou muito bem. Se você estiver apenas baixando os arquivos, o ZIP pode ser melhor. Se você for exibir os arquivos, o SVG parecerá superior.

Ao usar componentes Ajax, é possível iniciar vários downloads. Portanto, você precisa usar https://cwiki.apache.org/confluence/display/WICKET/AJAX+update+and+file+download+in+one+blow

Adicione uma instância de AJAXDownload para sua página ou qualquer outra coisa. Crie um AjaxButton e substitua onSubmit. Crie um AbstractAjaxTimerBehavior e inicie o download.

  button = new AjaxButton("button2") { private static final long serialVersionUID = 1L; @Override protected void onSubmit(AjaxRequestTarget target, Form< ?> form) { MultiSitePage.this.info(this); target.add(form); form.add(new AbstractAjaxTimerBehavior(Duration.milliseconds(1)) { @Override protected void onTimer(AjaxRequestTarget target) { download.initiate(target); } }); } 

Download feliz!

Abaixo do código 100% de trabalho.

Etapa 1 : cole o código abaixo no arquivo index.html

 < !DOCTYPE html>   Angular Test    

Passo 2 : Cole o código abaixo no arquivo index.js

 "use strict"; var x = angular.module('ang', []); x.controller('myController', function ($scope, $http) { var arr = [ {file:"http://localhost/angularProject/w3logo.jpg", fileName: "imageone"}, {file:"http://localhost/angularProject/cv.doc", fileName: "imagetwo"}, {file:"http://localhost/angularProject/91.png", fileName: "imagethree"} ]; $scope.files = function() { angular.forEach(arr, function(val, key) { $http.get(val.file) .then(function onSuccess(response) { console.log('res', response); var link = document.createElement('a'); link.setAttribute('download', val.fileName); link.setAttribute('href', val.file); link.style.display = 'none'; document.body.appendChild(link); link.click(); document.body.removeChild(link); }) .catch(function onError(error) { console.log('error', error); }) }) }; }); 

NOTA : Certifique-se de que todos os três arquivos que serão baixados serão colocados na mesma pasta, juntamente com os arquivos angularProject / index.html ou angularProject / index.js .

Isso funciona em todos os navegadores (IE11, Firefox, Edge, Chrome e Chrome Mobile) Meus documentos estão em vários elementos de seleção. Os navegadores parecem ter problemas quando você tenta fazer isso muito rápido … Então usei um tempo limite.

 //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)); } }); }); 

Esta é uma solução que usa 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); }); 

Obtendo lista de url com chamada ajax e, em seguida, use o plugin jquery para fazer o download de vários arquivos paralelos.

  $.ajax({ type: "POST", url: URL, contentType: "application/json; charset=utf-8", dataType: "json", data: data, async: true, cache: false, beforeSend: function () { blockUI("body"); }, complete: function () { unblockUI("body"); }, success: function (data) { //here data --> contains list of urls with comma seperated var listUrls= data.DownloadFilePaths.split(','); listUrls.forEach(function (url) { $.fileDownload(url); }); return false; }, error: function (result) { $('#mdlNoDataExist').modal('show'); } });