AngularJSまたはJavaScriptでダウンロードするファイルをどのように提供しますか?


96

非表示のテキストエリアにテキストがあります。ボタンがクリックされたときに、テキストを.txtファイルとしてダウンロードできるようにしたいと考えています。AngularJSまたはJavascriptを使用してこれは可能ですか?


1
どのブラウザをサポートしていますか?これはいくつかの創造的な方法(データURI、ブロブ、ブラウザの履歴APIなど)で解決できますが、それは実際に依存します。
Benjamin Gruenbaum 2013年

Angular File Saverは、時代遅れのブラウザーに適したポリフィルです。
georgeawg 2017年

回答:


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

素晴らしい解決策ですが、$scope.urlうまくいきませんでした。window.location代わりに使用しなければなりませんでした。
Gustavo Straube

7
アンカータグの前にunsafeが付いていることに気づきました。この問題を回避するには、$ compileProvider `.config(['$ compileProvider'、function($ compileProvider){$ compileProvider.aHrefSanitizationWhitelist(/ ^ \ s *(https?| ftp | mailto | tel | file | blob):/);} ` docs.angularjs.org/api/ng/provider/$compileProvider
coderman

10
download属性は、IEやSafariのバージョンでサポートされていないもののcaniuse.com/#feat=download
アーロン

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は必要に応じて私のために働きましたが、コードを説明できますか?
Harsh Daftary、2015

このソリューションのように!使用たとえば、サーバーからデータを取得するときに$http.get(...)設定してくださいをresponseType:'arraybuffer':ここで説明するようにstackoverflow.com/questions/21628378/...
ティム・ブーテ

Chrome(Win)で機能しますが、Safari(Mac)はブラウザでブロブされたファイルを開くだけです。(blob:https / ...)このようにして、このソリューションでは、約束が解決されるのを待つことができます。
sekky 2016年

26

これを試して

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

このサイトにアクセスしてください:)

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


7
downloadIEやSafariのいずれのバージョンでもまだサポートされていない属性に注意してください。こちらで確認してください。caniuse.com
=

Angularで使用すると、URLが$ urlRouterProviderになり、デフォルトのページにリダイレクトされます。ナビゲーションの代わりにファイルをダウンロードする解決策はありますか
HardikDG

誰かがそのようなリンクを投稿するとき、私はいつもそれをひいきにします。
slugmandrew

22

これは、別のブラウザウィンドウを開かなくても、JavaScriptで実行できます。

window.location.assign('url');

「url」をファイルへのリンクに置き換えます。ng-clickボタンからダウンロードをトリガーする必要がある場合、これを関数に入れて呼び出すことができます。


2
ダウンロードダイアログウィンドウを表示する代わりに、サイトをPDFドキュメントに置き換えます。
fdrv

ありがとう!魅力のように機能します。
サギ

14

現在作業中のプロジェクトでは、非表示のiFrameがあり、ダウンロードダイアログボックスを表示するには、ファイルのURLをiFrameにフィードする必要がありました。ボタンをクリックすると、コントローラーが動的URLを生成し、directive私が記述したカスタムがリストされている$ scopeイベントをトリガーします。ディレクティブは、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 2013

上記のディレクティブは、iframeの作成をスコープ外に配置すると機能しません。$ onはiframeを作成しますが、ブロードキャストの使用時に$ onイベントが呼び出されません
Kanagu

はい$ scope。$ broadcastは子供にのみ機能します。可能であれば、ディレクティブをトップレベルのスコープに置くことができます。
ケタン

12

あなたは、設定することができますlocation.hrefデータURIは、ユーザーのダウンロードをできるようにするデータを含みます。これ以外に、JavaScriptだけでそれを行う方法はないと思います。


これは私にとってはうまく機能し、私たちが試みていた他のすべてのもの、または上記で推奨されている複雑なアプローチであるIMHOよりもはるかにクリーンでした。Angularはそれを完全に無視します。または、別のウィンドウで開こうとする場合は、window.open()/ $ window.open()を使用することもできます。しかし、最新のブラウザーでポップアップブロッカーに遭遇します...
XML

1
Angular 1.3では、次のように$location.href変更$window.location.href
igortg

これは素晴らしい答えです。SO上の次のリンクは完全に動作する例を示します。stackoverflow.com/a/30889331/1625820
herrtim

7

unsafe:blob:nullが原因でファイルがダウンロードされない場合に備えて、それを追加したいだけです。ダウンロードボタンにカーソルを合わせると、サニタイズする必要があります。例えば、

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

app.config(function($ compileProvider){

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


4

同じ問題があり、別の解決策を見つけるのに何時間も費やしましたが、今はこの投稿のすべてのコメントに参加します。

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

バックエンド(春):

@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

静的URLは必要ありませんでした。すべてのajax操作を実行するためのAjaxFactoryがあります。ファクトリからURLを取得し、次のようにバインドしています。

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

ありがとう@AhlemMustapha

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.