web-dev-qa-db-fra.com

Comment puis-je laisser un utilisateur télécharger plusieurs fichiers quand un bouton est cliqué?

J'ai donc un serveur httpd en cours d'exécution qui a des liens vers un tas de fichiers. Disons que l'utilisateur sélectionne trois fichiers dans une liste de fichiers à télécharger et qu'ils se trouvent à l'adresse suivante:

mysite.com/file1 
mysite.com/file2
mysite.com/file3

Quand ils cliquent sur le bouton de téléchargement, je veux qu’ils téléchargent ces trois fichiers à partir des liens ci-dessus. 

Mon bouton de téléchargement ressemble à quelque chose comme:

var downloadButton = new Ext.Button({
  text: "Download",
  handler: function(){
    //download the three files here
  }
});
11
Grammin

La meilleure façon de faire est de compresser vos fichiers et de créer un lien vers cela:

L'autre solution peut être trouvée ici: Comment faire un lien ouvrir plusieurs pages lorsque l'on clique dessus

Qui dit ce qui suit:

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

Cela dit, je préférerais toujours compresser le fichier, car cette implémentation nécessite JavaScript et peut aussi parfois être bloquée en tant que popup.

14
Tanuj

C'est la méthode qui a fonctionné le mieux pour moi et qui n'a pas ouvert de nouveaux onglets, mais a simplement téléchargé les fichiers/images dont j'avais besoin

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 );
} );
11
Dan

Tu peux soit:

  1. Compressez les fichiers sélectionnés et renvoyez le fichier compressé.
  2. Ouvrez plusieurs fenêtres contextuelles, chacune demandant un téléchargement.

Remarque - la première option est objectivement meilleure.

Edit Option trois trouvée: https://stackoverflow.com/a/9425731/1803682

2
Matthew
    <!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();
    });
}         


}]);

exemple de plongeur: https://plnkr.co/edit/XynXRS7c742JPfCA3IpE?p=preview

1
suresh

J'ai résolu ce problème d'une manière différente en utilisant window.location. Cela fonctionne dans Chrome, qui est heureusement le seul navigateur que j'ai eu à supporter. Pourrait être utile à quelqu'un. J'avais initialement utilisé la réponse de Dan, qui nécessitait également le délai d'attente que j'ai utilisé ici ou le téléchargement d'un seul fichier.

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]);
  }        
};
1
Iain M Norman

Vous pouvez le faire en créant des événements de souris et en les envoyant au bouton. Sourse.

hrefList=['mysite.com/1.jpg', 'mysite.com/2.mp4', 'mysite.com/3.gif'];
buttonDownloadAll=document.createElement('a');
buttonDownloadAll.innerText='Download all';
buttonDownloadAll.href='';
buttonDownloadAll.download=false;
downloadFunc=function(){
    buttonDownloadAll.setAttribute('onclick', '');
    buttonDownloadAll.download=true;
    for(var i=0; i<hrefList.length-1; i++){
        buttonDownloadAll.href=hrefList[i];
        var clickEvent = document.createEvent('MouseEvent');
		clickEvent.initMouseEvent('click', true, true, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null); 
        buttonDownloadAll.dispatchEvent(clickEvent);
    }
    buttonDownloadAll.setAttribute('onclick', 'downloadFunc()');
    buttonDownloadAll.download=false;
    buttonDownloadAll.href='';
};
buttonDownloadAll.setAttribute('onclick', 'downloadFunc()');
document.body.appendChild(buttonDownloadAll);

0
PolyGlot

J'apprécie que l'exécution de l'événement click() sur l'élément a à l'intérieur d'un for loop pour le téléchargement de plusieurs fichiers ne fonctionne qu'avec un nombre limité de fichiers (10 fichiers dans mon cas). La seule raison qui me semblait logique était la rapidité d'exécution des téléchargements téléchargés. 

La solution qui a fonctionné pour moi était de ralentir l'exécution de l'événement click(). J'ai réalisé ceci avec le code source ci-dessous. 

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

J'exécute l'événement de téléchargement click() toutes les 300 ms. Lorsqu'il n'y a plus de fichiers à télécharger, urls.length == 0, j'exécute clearInterval sur la fonction interval.

0
Lukasz Dynowski

Cela fonctionne dans tous les navigateurs (IE11, Firefox, Microsoft Edge, Chrome et Chrome Mobile). Mes documents se trouvent dans plusieurs éléments sélectionnés. Les navigateurs semblent avoir des problèmes lorsque vous essayez de le faire trop rapidement ... J'ai donc utilisé un délai d'attente.

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

Cette solution utilise des promesses:

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);
});
0
Zach Painter