如何使用AngularJS或Javascript提供文件下载?


96

我在隐藏的文本区域中有一些文本。单击一个按钮后,我希望提供文本作为.txt文件下载。使用AngularJS或Javascript可以做到吗?


1
您支持哪些浏览器?这可以通过一些创造性的方式来解决(例如数据uri,blob,浏览器的历史记录API等),但这要视情况而定。
本杰明·格林鲍姆

Angular File Saver是不太现代的浏览器的很好的polyfill。
georgeawg

Answers:


110

您可以使用进行类似的操作Blob

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

在您的控制器中:

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

为了启用URL:

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

请注意

每次调用createObjectURL()时,都会创建一个新的对象URL,即使您已经为同一对象创建了一个URL。当您不再需要它们时,必须通过调用URL.revokeObjectURL()释放它们。当文档被卸载时,浏览器将自动释放这些文件。但是,为了获得最佳性能和内存使用率,如果可以安全地显式卸载它们,则应该这样做。

资料来源:MDN


3
现代浏览器和IE10 +
dave1010,2013年

@thriqon wow firefox + chrome真的向其他人展示了!
JonnyRaa 2014年

很好的解决方案,但$scope.url对我没有用。我不得不使用window.location
古斯塔沃·斯特劳布

7
我注意到锚标签的前缀是不安全的。为了解决这个问题,您需要使用$ compileProvider`.config(['$ compileProvider',function($ compileProvider){$ compileProvider.aHrefSanitizationWhitelist(/ ^ \ s *(https?| ftp | mailto | tel | file | blob):/);}` docs.angularjs.org/api/ng/provider/$compileProvider
coderman 2014年

10

33

只需单击按钮即可使用以下代码下载。

在HTML

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

在控制器中

$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根据需要为我工作,但是您可以解释代码吗?
严厉的达夫里2015年

喜欢这个解决方案!当使用从服务器,如获取数据$http.get(...)请务必将responseType:'arraybuffer'喜欢这里解释:stackoverflow.com/questions/21628378/...
蒂姆·布泰

可在Chrome(Win)中使用,但Safari(Mac)只会在浏览器中打开该文件。(blob:https / ...)像这样,该解决方案让我等待我的诺言被兑现。
塞基

26

试试这个

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

并访问此网站可能对您有帮助:)

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


7
注意download任何IE或Safari版本仍不支持的属性。在此处查看:caniuse.com/#feat=download
Pierre-Adrien Buisson,

当我将它与angular一起使用时,将网址带到$ urlRouterProvider并重定向到我的默认页面,是否有任何解决方案来下载文件而不是导航
HardikDG 2016年

当有人发布这样的链接时,我总是感到很光顾。
slugmandrew

22

这可以用javascript完成,而无需打开另一个浏览器窗口。

window.location.assign('url');

将“ url”替换为文件的链接。ng-click如果需要通过按钮触发下载,可以将其放在函数中并调用。


2
它将站点替换为Pdf doc,以显示下载对话框窗口。
fdrv

谢谢!奇迹般有效。
萨吉

14

在我们当前的工作项目中,我们有一个不可见的iFrame,我必须将文件的网址提供给iFrame以获取下载对话框。单击按钮后,控制器将生成动态URL,并触发一个$ scope事件,其中directive列出了我编写的自定义项。如果该指令尚不存在,则该指令会将iFrame附加到主体,并在其上设置url属性。

编辑:添加指令

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

该指令响应称为 downloadFile

所以在你的控制器中

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

1
代码段将有很大的帮助。
Sudhir N

当我将iframe创建置于scope之外时,上述指令对我不起作用。$ on创建iframe但使用广播时$ on事件未调用
Kanagu 2013年

是的$ scope。$ broadcast仅适用于儿童。如果可能,可以将指令放在顶级范围内。
Ketan

12

您可以设置location.href一个数据URI,其中包含要让用户下载的数据。除此之外,我认为仅凭JavaScript无法实现任何方法。


这对我来说非常有效,并且比我们正在尝试的所有其他尝试或IMHO(上面推荐的复杂方法)干净得多。Angular完全忽略了它。或者,如果您想尝试在另一个窗口中打开,也可以使用window.open()/ $ window.open()。但是您会在现代浏览器中遇到弹出窗口阻止程序……
XML

1
在Angular 1.3中,$location.href更改为$window.location.href
igortg,2015年

这是一个很好的答案。SO上的以下链接提供了完整的工作示例:stackoverflow.com/a/30889331/1625820
herrtim,

7

只是要添加一下,以防由于unsafe:blob:null ...而无法下载文件时,将鼠标悬停在下载按钮上时,必须对其进行清理。例如,

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

app.config(function($ compileProvider){

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

5

如果您可以在服务器上访问,请考虑按照此更常见的问题中的回答设置标题。

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

阅读有关该答案的评论时,建议使用比八位字节流更具体的Content-Type。


4

我遇到了同样的问题,花了很多时间找到不同的解决方案,现在我加入本文中的所有评论,希望对我有所帮助,我的答案已在Internet Explorer 11,Chrome和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>

指令:

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

        }
    }
})

在控制器中:

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

服务中:

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上):

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

谢谢,这确实对我有用,特别是因为我需要大文件传输。
Marcos Paulo SUS

3

这在角度上对我有用:

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

如果您要下载字符串,只需将fileURL更改为data:text/plain;base64,${btoa(theStringGoesHere)}
Chicken Soup

2

我不想使用静态网址。我有AjaxFactory用于执行所有ajax操作。我从工厂获取url,并按如下所示进行绑定。

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

谢谢@AhlemMustapha

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.