Làm cách nào để bạn cung cấp tệp để tải xuống bằng AngularJS hoặc Javascript?


96

Tôi có một số văn bản trong một văn bản ẩn. Khi một nút được nhấp vào, tôi muốn có văn bản được cung cấp để tải xuống dưới dạng .txttệp. Điều này có thể sử dụng AngularJS hoặc Javascript không?


1
Bạn hỗ trợ những trình duyệt nào? Điều này có thể được giải quyết theo một số cách sáng tạo (như data-uris, blobs, API lịch sử của trình duyệt, v.v.) nhưng điều đó thực sự phụ thuộc.
Benjamin Gruenbaum

Angular File Saver là một polyfill tốt cho các trình duyệt kém hiện đại hơn.
georgeawg

Câu trả lời:


110

Bạn có thể làm điều gì đó như thế này bằng cách sử dụng Blob.

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

trong bộ điều khiển của bạn:

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

để kích hoạt URL:

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

Xin lưu ý rằng

Mỗi lần bạn gọi createObjectURL (), một URL đối tượng mới sẽ được tạo, ngay cả khi bạn đã tạo một URL cho cùng một đối tượng. Mỗi cái này phải được giải phóng bằng cách gọi URL.revokeObjectURL () khi bạn không cần chúng nữa. Các trình duyệt sẽ tự động giải phóng chúng khi tài liệu được tải xuống; tuy nhiên, để có hiệu suất tối ưu và sử dụng bộ nhớ, nếu có những thời điểm an toàn khi bạn có thể dỡ bỏ chúng một cách rõ ràng, bạn nên làm như vậy.

Nguồn: MDN


3
Các trình duyệt hiện đại & IE10 +
dave1010 11/1213

@thriqon wow firefox + chrome thực sự hiển thị những người khác trên đó!
JonnyRaa

Giải pháp tuyệt vời, nhưng $scope.urlkhông hiệu quả với tôi. Tôi đã phải sử dụng window.locationthay thế.
Gustavo Straube vào

7
Tôi nhận thấy rằng sau đó thẻ liên kết có tiền tố là không an toàn. Để giải quyết vấn đề đó, bạn cần thêm 'blob' vào danh sách trắng trong app.js của mình bằng cách sử dụng $ compileProvider `.config (['$ compileProvider', function ($ compileProvider) {$ compileProvider.aHrefSanitizationWhitelist (/ ^ \ s * (https? | ftp | mailto | tel | file | blob): /);} ` docs.angularjs.org/api/ng/provider/$compileProvider
coderman

10
Các downloadthuộc tính không được hỗ trợ trong bất kỳ phiên bản trình duyệt IE hay Safari mặc dù caniuse.com/#feat=download
Aaron

33

Chỉ cần nhấp vào nút để tải xuống bằng cách sử dụng mã sau.

trong html

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

Trong bộ điều khiển

$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 đã làm việc cho tôi khi cần thiết, nhưng bạn có thể giải thích mã không?
Harsh Daftary

Thích giải pháp này! Khi lấy dữ liệu từ máy chủ, ví dụ như sử dụng $http.get(...)hãy đảm bảo đặt responseType:'arraybuffer'như được giải thích ở đây: stackoverflow.com/questions/21628378/…
Tim Büthe

Hoạt động trong Chrome (Win), nhưng Safari (Mac) chỉ mở tệp blobbed trong trình duyệt. (blob: https / ...) Như vậy, giải pháp này cho phép tôi chờ đợi những lời hứa của tôi được giải quyết.
sekky

26

Thử cái này

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

và truy cập trang web này, nó có thể hữu ích cho bạn :)

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


7
Hãy cẩn thận với downloadthuộc tính vẫn chưa được hỗ trợ bởi bất kỳ phiên bản IE và Safari nào. Kiểm tra nó tại đây: caniuse.com/#feat=download
Pierre-Adrien Buisson

Khi tôi sử dụng nó với góc cạnh, nó sẽ đưa url đến $ urlRouterProvider và chuyển hướng đến trang mặc định của tôi, có giải pháp nào để tải xuống tệp thay vì điều hướng
HardikDG

Tôi luôn thấy nó bảo trợ khi ai đó đăng một liên kết như thế.
slugmandrew

22

Điều này có thể được thực hiện trong javascript mà không cần phải mở một cửa sổ trình duyệt khác.

window.location.assign('url');

Thay thế 'url' bằng liên kết đến tệp của bạn. Bạn có thể đặt nó trong một hàm và gọi nó bằng ng-clicknếu bạn cần kích hoạt tải xuống từ một nút.


2
Nó thay thế trang web bằng tài liệu Pdf để hiển thị cửa sổ hộp thoại tải xuống.
fdrv

Cảm ơn! Hoạt động như một sự quyến rũ.
Sagi

14

Trong dự án hiện tại của chúng tôi tại nơi làm việc, chúng tôi có một iFrame vô hình và tôi phải cung cấp url của tệp cho iFrame để nhận được hộp thoại tải xuống. Khi nhấp vào nút, bộ điều khiển tạo url động và kích hoạt sự kiện $ scope trong đó directiveliệt kê một tùy chỉnh mà tôi đã viết. Chỉ thị sẽ nối iFrame vào phần thân nếu nó chưa tồn tại và đặt thuộc tính url trên đó.

EDIT: Thêm chỉ thị

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

Chỉ thị này phản hồi một sự kiện bộ điều khiển được gọi là downloadFile

vì vậy trong bộ điều khiển của bạn, bạn làm

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

1
Đoạn mã sẽ là một trợ giúp tuyệt vời.
Sudhir N

Chỉ thị nêu trên là không làm việc cho tôi, khi tôi đặt iframe phạm vi sáng tạo bên ngoài $ trên nó tạo ra iframe nhưng $ về sự kiện không được gọi khi sử dụng phát sóng.
Kanagu

Có $ scope. $ Broadcast chỉ hoạt động trên trẻ em. Bạn có thể đặt chỉ thị trên phạm vi cấp cao nhất nếu có thể.
Ketan 17/1213

12

Bạn có thể thiết lập location.hrefđể một dữ liệu URI có chứa các dữ liệu mà bạn muốn để tải về người dùng. Ngoài ra, tôi không nghĩ có cách nào để làm điều đó chỉ với JavaScript.


Điều này hiệu quả với tôi và sạch hơn nhiều so với tất cả những thứ khác mà chúng tôi đang thử, hoặc IMHO, các cách tiếp cận phức tạp được đề xuất ở trên. Angular hoàn toàn bỏ qua nó. Hoặc, bạn cũng có thể sử dụng window.open () / $ window.open () nếu bạn muốn thử mở trong một cửa sổ khác. Nhưng bạn sẽ chạy vào chức năng chặn popup trong các trình duyệt hiện đại ...
XML

1
Trong Angular 1.3, được $location.hrefđổi thành$window.location.href
igortg

Đây là một câu trả lời tuyệt vời. Liên kết sau trên SO cung cấp một ví dụ hoạt động đầy đủ: stackoverflow.com/a/30889331/1625820
herrtim

7

Chỉ muốn thêm điều đó trong trường hợp tệp không tải xuống được vì không an toàn: blob: null ... khi bạn di chuột qua nút tải xuống, bạn phải khử trùng nó. Ví dụ,

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

app.config (function ($ compileProvider) {

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

5

Nếu bạn có quyền truy cập trên máy chủ, hãy cân nhắc đặt tiêu đề như đã trả lời trong câu hỏi chung hơn này .

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

Đọc các nhận xét về câu trả lời đó, bạn nên sử dụng Loại nội dung cụ thể hơn là dòng octet.


4

Tôi đã gặp phải vấn đề tương tự và dành nhiều giờ để tìm các giải pháp khác nhau và bây giờ tôi tham gia tất cả các ý kiến ​​trong bài đăng này. Tôi hy vọng nó, sẽ hữu ích, câu trả lời của tôi đã được thử nghiệm chính xác trên Internet Explorer 11, Chrome và 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>

TRỰC TIẾP:

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

        }
    }
})

TRONG BỘ ĐIỀU KHIỂN:

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

PHỤC VỤ:

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 (trên XUÂN):

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

Cảm ơn, điều này thực sự hiệu quả với tôi, đặc biệt vì tôi cần chuyển tệp lớn.
Marcos Paulo SUS

3

Điều này làm việc cho tôi trong góc độ:

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

Nếu bạn có một chuỗi bạn muốn tải về, chỉ cần thay đổi fileURL đếndata:text/plain;base64,${btoa(theStringGoesHere)}
Chicken Soup

2

Tôi không muốn Url tĩnh. Tôi có AjaxFactory để thực hiện tất cả các hoạt động ajax. Tôi nhận được url từ nhà máy và liên kết nó như sau.

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

Cảm ơn @AhlemMustapha

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.