Frage Angularjs einfacher Datei-Download bewirkt, dass der Router umgeleitet wird


HTML:

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

Uploads erhalten einen eindeutigen Dateinamen, während der richtige Name in der Datenbank gespeichert wird. Ich möchte einen einfachen Datei-Download realisieren. Aber der obige Code leitet zu / wegen:

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

Ich habe es versucht

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

aber das öffnet nur die Datei in einem neuen Fenster.

Irgendwelche Ideen, wie man einen echten Download für jeden Dateityp ermöglicht?


75
2018-05-21 13:04


Ursprung


Antworten:


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

In folgenden Fällen werden Links nicht neu geschrieben; stattdessen, die   Der Browser lädt die Seite vollständig neu auf den ursprünglichen Link.

  • Links, die ein Zielelement enthalten Beispiel:
    <a href="/ext/link?a=b" target="_self">link</a> 

  • Absolute Links, die auf eine andere Domain verweisen Beispiel:
    <a href="http://angularjs.org/">link</a> 

  • Links beginnend mit '/', die zu einem anderen Basispfad führen, wenn die Basis definiert ist Beispiel:
    <a href="/not-my-base/link">link</a>

In Ihrem Fall sollten Sie also ein Zielattribut wie folgt hinzufügen ...

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

111
2018-05-21 13:40



Wir mussten auch eine Lösung entwickeln, die sogar mit Authentifizierungs-APIs funktionieren würde (vgl Dieser Artikel)

Mit AngularJS auf den Punkt gebracht, wie wir es gemacht haben:

Schritt 1: Erstellen Sie eine dedizierte Direktive

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

Schritt 2: Erstellen Sie eine Vorlage

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

Schritt 3: Verwenden Sie es

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

Dadurch wird eine blaue Schaltfläche angezeigt. Wenn Sie darauf klicken, wird eine PDF-Datei heruntergeladen (Vorsicht: das Backend muss die PDF-Datei in Base64-Kodierung liefern!) Und in die href-Datei eingefügt werden. Die Schaltfläche wird grün und wechselt den Text zu sparen. Der Benutzer kann erneut klicken und es wird ein Standarddownload-Dateidialog für die Datei angezeigt mein-toller.pdf.

In unserem Beispiel werden PDF-Dateien verwendet, aber anscheinend können Sie jedes Binärformat bereitstellen, sofern es korrekt codiert ist.


32
2017-09-25 07:47



Wenn Sie eine erweiterte Richtlinie benötigen, empfehle ich die von mir implementierte Lösung, die in Internet Explorer 11, Chrome und FireFox korrekt getestet wurde.

Ich hoffe es wird hilfreich sein.

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>

RICHTLINIE:

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

        }
    }
})

IN KONTROLLER:

$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=[];
                                });
                            }; 

IM DIENST:

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 (am FRÜHLING):

@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
2018-05-20 23:37



in der Vorlage

<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>

im Controller

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

0
2018-03-03 13:34



Ich weiß, dass dies ein alter Post ist, aber ich hatte Probleme, eine Lösung für den Stapelaustausch zu finden, die für einen automatischen Download mit einem eckigen Post funktionierte.

Hier ist meine Lösung (Eine Mischung aus jQuery / Angular / PHP):

PHP

    return array($filename,$url); 

Winkelansicht

    <a target="_self" id="downloadpdf" href={{downloadurl}} download={{filename}} style="display: none"></a>

Eckiger Controller

Sobald die Antwort mit der URL und dem Dateinamen empfangen wurde:

     $scope.downloadurl=data[1];
     $scope.filename=data[0];

     setTimeout(function () {
                        $('#downloadpdf')[0].click();
                    }, 1000);  

Ich habe dies auf eine Verzögerung von 1 Sekunde gesetzt, um den zu füllenden Werten Zeit zu geben, weil sie manchmal zu schnell ausgeführt wurde.

Ich hoffe es hilft!


-9
2018-02-14 22:24