web-dev-qa-db-fra.com

Le téléchargement de fichier simple Angularjs provoque la redirection du routeur

HTML:

<a href="mysite.com/uploads/asd4a4d5a.pdf" download="foo.pdf">

Les téléchargements obtiennent un nom de fichier unique tant que leur nom réel est conservé dans la base de données. Je veux réaliser un téléchargement de fichier simple. Mais le code ci-dessus redirige vers/à cause de:

$routeProvider.otherwise({
    redirectTo: '/', 
    controller: MainController
});

J'ai essayé avec 

$scope.download = function(resource){
    window.open(resource);
}

mais cela ouvre simplement le fichier dans une nouvelle fenêtre.

Des idées comment activer un téléchargement réel pour n'importe quel type de fichier?

77
Artjom Zabelin

https://docs.angularjs.org/guide/$location#html-link-rewriting

Dans les cas suivants, les liens ne sont pas réécrits; à la place, le Le navigateur effectuera un rechargement complet de la page vers le lien d'origine.

  • Liens contenant l'élément cible Exemple:
    <a href="/ext/link?a=b" target="_self">link</a> 

  • Liens absolus qui vont vers un domaine différent Exemple:
    <a href="http://angularjs.org/">link</a> 

  • Liens commençant par '/' qui mènent à un chemin de base différent lorsque la base est définie Exemple:
    <a href="/not-my-base/link">link</a>

Donc, dans votre cas, vous devriez ajouter un attribut cible comme suit ...

<a target="_self" href="example.com/uploads/asd4a4d5a.pdf" download="foo.pdf">
114
jessegavin

Nous devions également développer une solution qui fonctionnerait même avec des API nécessitant une authentification (voir cet article )

En utilisant AngularJS en quelques mots, voici comment nous l’avons fait:

Étape 1: Créer une directive dédiée

// jQuery needed, uses Bootstrap classes, adjust the path of templateUrl
app.directive('pdfDownload', function() {
return {
    restrict: 'E',
    templateUrl: '/path/to/pdfDownload.tpl.html',
    scope: true,
    link: function(scope, element, attr) {
        var anchor = element.children()[0];

        // When the download starts, disable the link
        scope.$on('download-start', function() {
            $(anchor).attr('disabled', 'disabled');
        });

        // When the download finishes, attach the data to the link. Enable the link and change its appearance.
        scope.$on('downloaded', function(event, data) {
            $(anchor).attr({
                href: 'data:application/pdf;base64,' + data,
                download: attr.filename
            })
                .removeAttr('disabled')
                .text('Save')
                .removeClass('btn-primary')
                .addClass('btn-success');

            // Also overwrite the download pdf function to do nothing.
            scope.downloadPdf = function() {
            };
        });
    },
    controller: ['$scope', '$attrs', '$http', function($scope, $attrs, $http) {
        $scope.downloadPdf = function() {
            $scope.$emit('download-start');
            $http.get($attrs.url).then(function(response) {
                $scope.$emit('downloaded', response.data);
            });
        };
    }] 
});

Étape 2: créer un modèle

<a href="" class="btn btn-primary" ng-click="downloadPdf()">Download</a>

Étape 3: Utilisez-le

<pdf-download url="/some/path/to/a.pdf" filename="my-awesome-pdf"></pdf-download>

Cela rendra un bouton bleu. Lorsque vous cliquez dessus, un PDF sera téléchargé (Attention: le système doit fournir le PDF en codage Base64!) Et le mettre dans le fichier href. Le bouton devient vert et fait basculer le texte sur Enregistrer. L'utilisateur peut cliquer à nouveau et une boîte de dialogue de téléchargement standard pour le fichier my-awesome.pdf s'affichera.

Notre exemple utilise des fichiers PDF, mais apparemment, vous pouvez fournir n’importe quel format binaire, s’il est correctement codé.

32
aix

Si vous avez besoin d'une directive plus avancée, je vous recommande la solution que j'ai implémentée, correctement testée sur Internet Explorer 11, Chrome et FireFox.

J'espère que cela vous sera utile.

HTML:

<a href="#" class="btn btn-default" file-name="'fileName.extension'"  ng-click="getFile()" file-download="myBlobObject"><i class="fa fa-file-Excel-o"></i></a>

DIRECTIVE:

directive('fileDownload',function(){
    return{
        restrict:'A',
        scope:{
            fileDownload:'=',
            fileName:'=',
        },

        link:function(scope,elem,atrs){


            scope.$watch('fileDownload',function(newValue, oldValue){

                if(newValue!=undefined && newValue!=null){
                    console.debug('Downloading a new file'); 
                    var isFirefox = typeof InstallTrigger !== 'undefined';
                    var isSafari = Object.prototype.toString.call(window.HTMLElement).indexOf('Constructor') > 0;
                    var isIE = /*@cc_on!@*/false || !!document.documentMode;
                    var isEdge = !isIE && !!window.StyleMedia;
                    var isChrome = !!window.chrome && !!window.chrome.webstore;
                    var isOpera = (!!window.opr && !!opr.addons) || !!window.opera || navigator.userAgent.indexOf(' OPR/') >= 0;
                    var isBlink = (isChrome || isOpera) && !!window.CSS;

                    if(isFirefox || isIE || isChrome){
                        if(isChrome){
                            console.log('Manage Google Chrome download');
                            var url = window.URL || window.webkitURL;
                            var fileURL = url.createObjectURL(scope.fileDownload);
                            var downloadLink = angular.element('<a></a>');//create a new  <a> tag element
                            downloadLink.attr('href',fileURL);
                            downloadLink.attr('download',scope.fileName);
                            downloadLink.attr('target','_self');
                            downloadLink[0].click();//call click function
                            url.revokeObjectURL(fileURL);//revoke the object from URL
                        }
                        if(isIE){
                            console.log('Manage IE download>10');
                            window.navigator.msSaveOrOpenBlob(scope.fileDownload,scope.fileName); 
                        }
                        if(isFirefox){
                            console.log('Manage Mozilla Firefox download');
                            var url = window.URL || window.webkitURL;
                            var fileURL = url.createObjectURL(scope.fileDownload);
                            var a=elem[0];//recover the <a> tag from directive
                            a.href=fileURL;
                            a.download=scope.fileName;
                            a.target='_self';
                            a.click();//we call click function
                        }


                    }else{
                        alert('SORRY YOUR BROWSER IS NOT COMPATIBLE');
                    }
                }
            });

        }
    }
})

DANS LE CONTROLEUR:

$scope.myBlobObject=undefined;
$scope.getFile=function(){
        console.log('download started, you can show a wating animation');
        serviceAsPromise.getStream({param1:'data1',param1:'data2', ...})
        .then(function(data){//is important that the data was returned as Aray Buffer
                console.log('Stream download complete, stop animation!');
                $scope.myBlobObject=new Blob([data],{ type:'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'});
        },function(fail){
                console.log('Download Error, stop animation and show error message');
                                    $scope.myBlobObject=[];
                                });
                            }; 

EN SERVICE:

function getStream(params){
                 console.log("RUNNING");
                 var deferred = $q.defer();

                 $http({
                     url:'../downloadURL/',
                     method:"PUT",//you can use also GET or POST
                     data:params,
                     headers:{'Content-type': 'application/json'},
                     responseType : 'arraybuffer',//THIS IS IMPORTANT
                    })
                    .success(function (data) {
                        console.debug("SUCCESS");
                        deferred.resolve(data);
                    }).error(function (data) {
                         console.error("ERROR");
                         deferred.reject(data);
                    });

                 return deferred.promise;
                };

BACKEND (sur PRINTEMPS):

@RequestMapping(value = "/downloadURL/", method = RequestMethod.PUT)
public void downloadExcel(HttpServletResponse response,
        @RequestBody Map<String,String> spParams
        ) throws IOException {
        OutputStream outStream=null;
outStream = response.getOutputStream();//is important manage the exceptions here
ObjectThatWritesOnOutputStream myWriter= new ObjectThatWritesOnOutputStream();// note that this object doesn exist on Java,
ObjectThatWritesOnOutputStream.write(outStream);//you can configure more things here
outStream.flush();
return;
}
8
havelino

dans le modèle

<md-button class="md-fab md-mini md-warn md-ink-ripple" ng-click="export()" aria-label="Export">
<md-icon class="material-icons" alt="Export" title="Export" aria-label="Export">
    system_update_alt
</md-icon></md-button>

dans le contrôleur

     $scope.export = function(){ $window.location.href = $scope.export; };
0
nat_jea