2013-05-13 56 views
87

我在隱藏的textarea中有一些文字。當點擊一個按鈕時,我想將提供的文本作爲.txt文件提供下載。這可能使用AngularJS或Javascript嗎?如何使用AngularJS或Javascript爲文件下載?

+1

你支持哪些瀏覽器?這可以通過一些創造性的方式來解決(比如data-uris,blob,瀏覽器的歷史API等),但這真的取決於。 – 2013-05-13 18:07:40

+0

[Angular File Saver](https://github.com/alferov/angular-file-saver)是較不現代的瀏覽器的良好補丁。 – georgeawg 2017-03-12 23:19:38

回答

98

您可以使用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(時間),一即使您已經創建了一個f,也會創建新的對象URL或同一個對象。當你不再需要它們時,每一個都必須通過調用URL.revokeObjectURL()來釋放。當文檔被卸載時,瀏覽器會自動釋放這些文件;但是,爲了獲得最佳性能和內存使用情況,如果有明確卸載它們的安全時間,則應該這樣做。

來源:MDN

+2

有趣的是,我不知道瀏覽器對此支持的是 – 2013-05-13 12:38:31

+17

http: //caniuse.com/bloburls – thriqon 2013-09-30 05:26:34

+2

現代瀏覽器和IE10 + – dave1010 2013-12-11 17:10:50

11

您可以將location.href設置爲data URI,其中包含要讓用戶下載的數據。除此之外,我不認爲有什麼方法可以用JavaScript來完成。

+0

這對我來說很好,比我們嘗試的所有其他事情更清潔,或者恕我直言,上面推薦的複雜方法。 Angular完全忽略它。或者,如果您想嘗試在另一個窗口中打開,也可以使用window.open()/ $ window.open()。但是你會碰到現代瀏覽器中的彈出窗口攔截器...... – XML 2014-01-06 02:29:20

+1

在Angular 1.3中,'$ location.href'改爲'$ window.location.href' – itghisi 2015-05-12 18:39:33

14

在我們當前的工作項目,我們有一個無形的iFrame,我不得不養活的URL文件的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

代碼片段將是一個很大的幫助。 – 2013-10-08 09:21:20

+0

添加了代碼片段。 – Ketan 2013-10-08 19:14:22

+0

上面的指令不適用於我,當我將iframe創建爲範圍以外時,$創建iframe,但$ on事件在使用廣播時未調用 – Kanagu 2013-12-17 07:31:02

6

只想補充一點的情況下,它不會因爲不安全而下載文件:blob:null ...當您將鼠標懸停在下載按鈕上時,必須對其進行清理。例如,

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

app。配置(函數($ compileProvider){

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

試試這個

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

和訪問這個網站也可能對你有幫助:)

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

+0

作品像魅力。 Mucho gracias(y) – om471987 2014-05-05 21:56:04

+7

請注意任何IE或Safari版本都不支持的「下載」屬性。檢查它在這裏:http://caniuse.com/#feat=download – 2014-11-14 11:18:22

+0

當我使用它與角度它採取URL到$ urlRouterProvider並重定向到我的默認頁面,有沒有任何解決方案下載文件,而不是導航 – HardikDG 2016-02-25 03:46:00

2

我沒有想靜態URL。我有用於執行所有ajax操作的AjaxFactory。我從工廠獲取url並按如下方式進行綁定。

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

感謝@AhlemMustapha

19

這可以在JavaScript中完成,而無需打開另一個瀏覽器窗口。

window.location.assign('url'); 

將「url」替換爲指向您文件的鏈接。你可以把它放在一個函數中,如果你需要觸發一個按鈕的下載,可以用ng-click來調用它。

+2

它用Pdf文檔替換網站,而不是顯示下載對話窗口。 – fdrv 2016-04-06 05:25:19

26

只需點擊按鈕使用下面的代碼下載。

在HTML

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

在控制器

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

+1

這是如何在Safari + IE中使用的? – 2015-03-18 14:36:07

+1

@Amrut 根據需要爲我工作,但你能解釋代碼嗎? – 2015-07-29 08:29:53

+0

喜歡這個解決方案!當從服務器獲取數據時,例如使用'$ http.get(...)'確保設置'responseType:'arraybuffer''就像這裏解釋的:http://stackoverflow.com/questions/21628378/angularjs-display-blob-pdf-in-an -angular-app – 2015-09-01 15:33:43

3

我有德同樣的問題,花很多時間找迪不同的解決方案,現在我加入了這篇文章中的所有評論。我希望它會有幫助,我的答案在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 = /*@[email protected]*/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(春):

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

謝謝,這真的對我有用,特別是因爲我需要大文件傳輸。 – 2017-02-08 15:56:05

3

如果你有機會到服務器上,考慮設置標頭,answered in this more general question

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

閱讀對該答案的評論,建議使用比八位組流更具體的內容類型。