Bagaimana Anda melayani file untuk diunduh dengan AngularJS atau Javascript?


96

Saya memiliki beberapa teks di textarea tersembunyi. Ketika sebuah tombol diklik, saya ingin teks tersebut ditawarkan untuk diunduh sebagai .txtfile. Apakah ini mungkin menggunakan AngularJS atau Javascript?


1
Browser apa yang Anda dukung? Ini dapat diselesaikan dengan beberapa cara kreatif (seperti data-uris, blob, API riwayat browser, dll) tetapi itu sangat bergantung.
Benjamin Gruenbaum

Angular File Saver adalah polyfill yang bagus untuk browser yang kurang modern.
georgeawg

Jawaban:


110

Anda dapat melakukan hal seperti ini dengan menggunakan Blob.

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

di pengontrol Anda:

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

untuk mengaktifkan URL:

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

Harap dicatat bahwa

Setiap kali Anda memanggil createObjectURL (), URL objek baru dibuat, meskipun Anda sudah membuatnya untuk objek yang sama. Masing-masing harus dilepaskan dengan memanggil URL.revokeObjectURL () saat Anda tidak lagi membutuhkannya. Browser akan merilisnya secara otomatis saat dokumen dibongkar; namun, untuk kinerja dan penggunaan memori yang optimal, jika ada waktu aman saat Anda dapat membongkarnya secara eksplisit, Anda harus melakukannya.

Sumber: MDN


3
Browser modern & IE10 +
dave1010

@thriqon wow firefox + chrome benar-benar menampilkan yang lain di sana!
JonnyRaa

Solusi hebat, tetapi $scope.urltidak berhasil untuk saya. Saya harus menggunakan window.locationsebagai gantinya.
Gustavo Straube

7
Saya perhatikan bahwa kemudian tag anchor diawali dengan unsafe. Untuk menyiasati itu, Anda perlu menambahkan 'blob' ke daftar putih di app.js, menggunakan $ compileProvider `.config (['$ compileProvider', function ($ compileProvider) {$ compileProvider.aHrefSanitizationWhitelist (/ ^ \ s * (https? | ftp | mailto | tel | file | blob): /);} ` docs.angularjs.org/api/ng/provider/$compileProvider
coderman

10
The downloadatribut tidak didukung dalam versi IE atau Safari meskipun caniuse.com/#feat=download
Aaron

33

Cukup klik tombol untuk mengunduh menggunakan kode berikut.

dalam html

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

Dalam pengontrol

$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 bekerja untuk saya sesuai kebutuhan, tetapi dapatkah Anda menjelaskan kodenya?
Harsh Daftary

Suka solusi ini! Saat mendapatkan data dari server, misalnya menggunakan $http.get(...)pastikan untuk mengatur responseType:'arraybuffer'seperti yang dijelaskan di sini: stackoverflow.com/questions/21628378/…
Tim Büthe

Berfungsi di Chrome (Win), tetapi Safari (Mac) hanya membuka file blobbed di browser. (blob: https / ...) Seperti itu solusi ini memungkinkan saya menunggu janji saya diselesaikan.
sekky

26

Coba ini

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

dan kunjungi situs ini, ini bisa membantu Anda :)

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


7
Waspadai downloadatribut yang masih belum didukung oleh versi IE atau Safari. Lihat di sini: caniuse.com/#feat=download
Pierre-Adrien Buisson

Ketika saya menggunakannya dengan sudut, itu mengambil url ke $ urlRouterProvider dan mengarahkan ke halaman default saya, apakah ada solusi untuk mengunduh file daripada navigasi
HardikDG

Saya selalu merasa menggurui ketika seseorang memposting tautan seperti itu.
slugmandrew

22

Ini dapat dilakukan dalam javascript tanpa perlu membuka jendela browser lain.

window.location.assign('url');

Ganti 'url' dengan tautan ke file Anda. Anda dapat menempatkan ini dalam sebuah fungsi dan memanggilnya dengan ng-clickjika Anda perlu memicu unduhan dari sebuah tombol.


2
Ini menggantikan situs dengan dokumen Pdf sebagai gantinya untuk menampilkan jendela dialog unduhan.
fdrv

Terima kasih! Bekerja seperti pesona.
Sagi

14

Dalam proyek kami saat ini di tempat kerja kami memiliki iFrame yang tidak terlihat dan saya harus memberi makan url untuk file tersebut ke iFrame untuk mendapatkan kotak dialog unduhan. Pada klik tombol, pengontrol menghasilkan url dinamis dan memicu peristiwa $ scope di mana kebiasaan yang directivesaya tulis, terdaftar. Direktif akan menambahkan iFrame ke badan jika belum ada dan menyetel atribut url di atasnya.

EDIT: Menambahkan perintah

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

Direktif ini menanggapi peristiwa pengontrol yang disebut downloadFile

jadi di pengontrol Anda, Anda melakukannya

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

1
Potongan kode akan sangat membantu.
Sudhir N

Arahan di atas tidak berfungsi untuk saya, ketika saya meletakkan pembuatan iframe di luar cakupan. $ Di atasnya membuat iframe tetapi $ pada acara tidak menelepon saat menggunakan siaran
Kanagu

Ya $ scope. $ Broadcast hanya berfungsi untuk anak-anak. Anda dapat meletakkan arahan pada cakupan tingkat atas jika memungkinkan.
Ketan

12

Anda dapat menyetel location.hrefke URI data yang berisi data yang Anda inginkan agar dapat diunduh pengguna. Selain itu, menurut saya tidak ada cara untuk melakukannya hanya dengan JavaScript.


Ini bekerja sangat baik untuk saya, dan jauh lebih bersih daripada semua hal lain yang kami coba, atau IMHO, pendekatan rumit yang direkomendasikan di atas. Angular mengabaikannya sepenuhnya. Atau, Anda juga dapat menggunakan window.open () / $ window.open () jika Anda ingin mencoba membuka di jendela lain. Tetapi Anda akan menemukan pemblokir popup di peramban modern ...
XML

1
Di Angular 1.3, $location.hrefdiubah menjadi$window.location.href
igortg

Ini jawaban yang bagus. Tautan berikut di SO memberikan contoh yang berfungsi penuh: stackoverflow.com/a/30889331/1625820
herrtim

7

Hanya ingin menambahkannya jika tidak mengunduh file karena tidak aman: blob: null ... saat Anda mengarahkan kursor ke tombol unduh, Anda harus membersihkannya. Misalnya,

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

app.config (function ($ compileProvider) {

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

5

Jika Anda memiliki akses ke di server, pertimbangkan untuk menyetel header seperti yang dijawab dalam pertanyaan yang lebih umum ini .

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

Membaca komentar tentang jawaban itu, disarankan untuk menggunakan Jenis Konten yang lebih spesifik daripada aliran oktet.


4

Saya memiliki masalah yang sama dan menghabiskan berjam-jam menemukan solusi yang berbeda, dan sekarang saya bergabung dengan semua komentar di posting ini. Saya harap ini, akan membantu, jawaban saya telah diuji dengan benar di Internet Explorer 11, Chrome dan FireFox.

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>

PENGARAHAN :

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

        }
    }
})

DI CONTROLLER:

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

DALAM PELAYANAN:

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

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

Terima kasih, ini benar-benar berhasil untuk saya, terutama karena saya membutuhkan transfer file yang besar.
Marcos Paulo SUS

3

Ini bekerja untuk saya dalam sudut:

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

Jika Anda memiliki string yang ingin Anda unduh, cukup ubah fileURL menjadidata:text/plain;base64,${btoa(theStringGoesHere)}
Chicken Soup

2

Saya tidak ingin Static Url. Saya memiliki AjaxFactory untuk melakukan semua operasi ajax. Saya mendapatkan url dari pabrik dan mengikatnya sebagai berikut.

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

Terima kasih @AhlemMustapha

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.