AngularJS veya Javascript ile bir dosyayı indirmek için nasıl sunarsınız?


97

Gizli bir metin alanında bazı metinlerim var. Bir düğmeye tıklandığında, metnin bir .txtdosya olarak indirilmek üzere sunulmasını istiyorum . Bu, AngularJS veya Javascript kullanılarak mümkün müdür?


1
Hangi tarayıcıları destekliyorsunuz? Bu, bazı yaratıcı yollarla (data-uris, blob'lar, tarayıcının geçmiş API'si vb.) Çözülebilir, ancak bu gerçekten bağlıdır.
Benjamin Gruenbaum

Açısal Dosya Tasarrufu , daha az modern tarayıcılar için iyi bir çoklu dolgudur.
georgeawg

Yanıtlar:


111

Kullanarak böyle bir şey yapabilirsiniz Blob.

<a download="content.txt" ng-href="{{ url }}">download</a>

denetleyicinizde:

var content = 'file content for example';
var blob = new Blob([ content ], { type : 'text/plain' });
$scope.url = (window.URL || window.webkitURL).createObjectURL( blob );

URL'yi etkinleştirmek için:

app = angular.module(...);
app.config(['$compileProvider',
    function ($compileProvider) {
        $compileProvider.aHrefSanitizationWhitelist(/^\s*(https?|ftp|mailto|tel|file|blob):/);
}]);

Lütfen bunu not al

CreateObjectURL () öğesini her çağırdığınızda, aynı nesne için zaten bir tane oluşturmuş olsanız bile yeni bir nesne URL'si oluşturulur. Artık ihtiyacınız kalmadığında URL.revokeObjectURL () çağrılarak bunların her biri serbest bırakılmalıdır. Tarayıcılar, belge kaldırıldığında bunları otomatik olarak serbest bırakır; ancak, en iyi performans ve bellek kullanımı için, bunları açıkça kaldırabileceğiniz güvenli zamanlar varsa, bunu yapmalısınız.

Kaynak: MDN


3
Modern tarayıcılar ve IE10 +
dave1010

@thriqon vay firefox + chrome gerçekten diğerlerini orada gösteriyor!
JonnyRaa

Harika bir çözüm, ama $scope.urlbenim için işe yaramadı. Onun window.locationyerine kullanmak zorunda kaldım .
Gustavo Straube

7
Bağlantı etiketinin önekinin güvenli olmadığını fark ettim. Bunu aşmak için $ compileProvider ".config (['$ compileProvider', function ($ compileProvider) {$ compileProvider.aHrefSanitizationWhitelist (/ ^ \ s * (https? | ftp | mailto | tel | dosya | blob): /);} ` docs.angularjs.org/api/ng/provider/$compileProvider
coderman

10
Bu downloadözellik, caniuse.com/#feat=download
Aaron

33

Aşağıdaki kodu kullanarak indirmek için düğmeye tıklamanız yeterlidir.

html olarak

<a class="btn" ng-click="saveJSON()" ng-href="{{ url }}">Export to JSON</a>

Denetleyicide

$scope.saveJSON = function () {
			$scope.toJSON = '';
			$scope.toJSON = angular.toJson($scope.data);
			var blob = new Blob([$scope.toJSON], { type:"application/json;charset=utf-8;" });			
			var downloadLink = angular.element('<a></a>');
                        downloadLink.attr('href',window.URL.createObjectURL(blob));
                        downloadLink.attr('download', 'fileName.json');
			downloadLink[0].click();
		};


1
@Amrut gerektiği gibi benim için çalıştı, ama kodu açıklayabilir misin?
Sert Daftary

Bu çözüm gibi! Verileri sunucudan alırken, örneğin burada açıklandığı gibi $http.get(...)ayarladığınızdan emin olun responseType:'arraybuffer': stackoverflow.com/questions/21628378/…
Tim Büthe

Chrome'da (Win) çalışır, ancak Safari (Mac) blobbed dosyasını tarayıcıda açar. (blob: https / ...) Bu çözüm, sözlerimin çözülmesini beklememe izin veriyor.
sekky

26

Bunu dene

<a target="_self" href="mysite.com/uploads/ahlem.pdf" download="foo.pdf">

ve bu siteyi ziyaret edin, sizin için yararlı olabilir :)

http://docs.angularjs.org/guide/


7
downloadHala herhangi bir IE veya Safari sürümü tarafından desteklenmeyen özniteliğe dikkat edin . Buradan bir göz atın: caniuse.com/#feat=download
Pierre-Adrien Buisson

Açısal olarak kullandığımda url'yi $ urlRouterProvider'a götürür ve varsayılan sayfama yönlendirir, navigasyon yerine dosya indirmek için herhangi bir çözüm var mı
HardikDG

Birisi böyle bir bağlantı yayınladığında her zaman patronluk taslayan buluyorum.
slugmandrew

23

Bu, başka bir tarayıcı penceresi açmaya gerek kalmadan javascript ile yapılabilir.

window.location.assign('url');

"Url" yi dosyanızın bağlantısıyla değiştirin. Bunu bir işleve koyabilir ng-clickve indirmeyi bir düğmeden tetiklemeniz gerekiyorsa ile çağırabilirsiniz.


2
İndirme iletişim penceresini göstermek yerine siteyi Pdf belgeyle değiştirir.
fdrv

Teşekkürler! Tıkır tıkır çalışıyor.
Sagi

14

İşteki mevcut projemizde görünmez bir iFrame'imiz vardı ve bir indirme iletişim kutusu almak için dosyanın URL'sini iFrame'e beslemek zorunda kaldım. Düğmeye tıklandığında, denetleyici dinamik url'yi oluşturur ve directiveyazdığım bir özelin listelendiği bir $ kapsam olayını tetikler . Yönerge, halihazırda mevcut değilse gövdeye bir iFrame ekleyecek ve url özniteliğini onun üzerinde ayarlayacaktır.

DÜZENLEME: Bir yönerge ekleme

appModule.directive('fileDownload', function ($compile) {
    var fd = {
        restrict: 'A',
        link: function (scope, iElement, iAttrs) {

            scope.$on("downloadFile", function (e, url) {
                var iFrame = iElement.find("iframe");
                if (!(iFrame && iFrame.length > 0)) {
                    iFrame = $("<iframe style='position:fixed;display:none;top:-1px;left:-1px;'/>");
                    iElement.append(iFrame);
                }

                iFrame.attr("src", url);


            });
        }
    };

    return fd;
});

Bu yönerge adı verilen bir denetleyici olayına yanıt verir downloadFile

yani kontrol cihazında yaparsın

$scope.$broadcast("downloadFile", url);

1
Kod parçacığı çok yardımcı olur.
Sudhir N

Yukarıdaki yönerge, iframe oluşturmayı kapsamın dışına koyduğumda benim için çalışmıyor. $ On iframe oluşturuyor ancak yayın kullanırken $ on olayı çağırmıyor
Kanagu

Evet $ kapsam. $ Yayını yalnızca çocuklarda çalışır. Yönergeyi mümkünse en üst düzey kapsama koyabilirsiniz.
Ketan

12

Kullanıcının indirmesine izin vermek istediğiniz verileri içeren location.hrefbir veri URI'si ayarlayabilirsiniz . Bunun yanı sıra, bunu sadece JavaScript ile yapmanın bir yolu olduğunu düşünmüyorum.


Bu benim için harika çalışıyor ve denediğimiz tüm diğer şeylerden veya yukarıda önerilen karmaşık yaklaşımlardan IMHO'dan çok daha temizdi. Angular onu tamamen görmezden geliyor. Ya da başka bir pencerede açmayı denemek istiyorsanız window.open () / $ window.open () kullanabilirsiniz. Ancak modern tarayıcılarda açılır pencere engelleyicileriyle karşılaşacaksınız ...
XML

1
Angular 1.3'te, $location.hrefdeğiştirildi$window.location.href
igortg

Bu harika bir cevap. SO ile ilgili aşağıdaki bağlantı tam bir çalışma örneği sağlar: stackoverflow.com/a/30889331/1625820
herrtim

7

Dosyayı güvenli olmadığı için indirememesi durumunda eklemek ister misiniz: blob: null ... indirme düğmesinin üzerine geldiğinizde, onu dezenfekte etmeniz gerekir. Örneğin,

var app = angular.module ('uygulama', []);

app.config (function ($ compileProvider) {

$compileProvider.aHrefSanitizationWhitelist(/^\s*(|blob|):/);

5

Sunucuya erişiminiz varsa, başlıkları bu daha genel soruda yanıtlandığı gibi ayarlamayı düşünün .

Content-Type: application/octet-stream
Content-Disposition: attachment;filename=\"filename.xxx\"

Bu cevaba ilişkin yorumları okurken, sekizli akıştan daha özel bir İçerik Türü kullanmanız önerilir.


4

Aynı problemi yaşadım ve farklı çözümler bulmak için saatler harcadım ve şimdi bu yazıdaki tüm yorumlara katılıyorum, umarım, yardımcı olur, cevabım Internet Explorer 11, Chrome ve FireFox üzerinde doğru bir şekilde test edildi.

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>

YÖNERGE:

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

        }
    }
})

DENETLEYİCİDE:

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

SERVİSTE:

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 (SPRING tarihinde):

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

Teşekkürler, özellikle büyük dosya transferlerine ihtiyacım olduğu için bu benim için gerçekten işe yaradı.
Marcos Paulo SUS

3

Bu benim için açısal olarak çalıştı:

var a = document.createElement("a");
a.href = 'fileURL';
a.download = 'fileName';
a.click();

İndirmek istediğiniz bir dizeniz varsa, fileURL'yidata:text/plain;base64,${btoa(theStringGoesHere)}
Chicken Suop olarak

2

Statik URL istemedim. Tüm ajax işlemlerini yapmak için AjaxFactory'ye sahibim. Fabrikadan url alıyorum ve aşağıdaki gibi bağlıyorum.

<a target="_self" href="{{ file.downloadUrl + '/' + order.OrderId + '/' + fileName }}" download="{{fileName}}">{{fileName}}</a>

Teşekkürler @AhlemMustapha

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.