AngularJS 또는 Javascript로 다운로드 할 파일을 어떻게 제공합니까?


96

숨겨진 텍스트 영역에 텍스트가 있습니다. 버튼을 클릭하면 텍스트를 파일로 다운로드 할 수 있도록하고 싶습니다 .txt. AngularJS 또는 Javascript를 사용하여 가능합니까?


1
어떤 브라우저를 지원합니까? 이것은 몇 가지 창의적인 방법 (data-uris, blob, 브라우저의 히스토리 API 등)으로 해결할 수 있지만 실제로는 다릅니다.
Benjamin Gruenbaum 2013 년

Angular File Saver 는 덜 현대적인 브라우저에 적합한 폴리 필입니다.
georgeawg

답변:


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.revokeObjectURL ()을 호출하여 이들 각각을 해제해야합니다. 브라우저는 문서가 언로드 될 때 자동으로이를 해제합니다. 그러나 최적의 성능과 메모리 사용을 위해 명시 적으로 언로드 할 수있는 안전한 시간이 있다면 그렇게해야합니다.

출처 : MDN


3
최신 브라우저 및 IE10 +
dave1010

@thriqon wow firefox + chrome이 실제로 다른 사람들을 보여줍니다!
JonnyRaa

훌륭한 솔루션이지만 $scope.url나를 위해 일하지 않았습니다. window.location대신 사용해야 했습니다.
Gustavo Straube 2014 년

7
앵커 태그에 안전하지 않은 접두사가 붙는 것을 알았습니다. 이 문제를 해결하려면 $ compileProvider`.config ([ '$ compileProvider', function ($ compileProvider) {$ compileProvider.aHrefSanitizationWhitelist (/ ^)를 사용하여 app.js의 화이트리스트에 'blob'을 추가해야합니다. \ 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

이 솔루션처럼! 사용하여 서버, 예로부터 데이터를 가져 오는 경우 $http.get(...)설정해야합니다을 responseType:'arraybuffer': 여기에서 설명하는 것처럼 stackoverflow.com/questions/21628378/...
팀 쎄

Chrome (Win)에서 작동하지만 Safari (Mac)는 브라우저에서 얼룩 파일을 엽니 다. (blob : https / ...) 이렇게이 솔루션을 사용하면 약속이 해결되기를 기다릴 수 있습니다.
sekky

26

이 시도

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

이 사이트를 방문하면 도움이 될 것입니다. :)

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


7
downloadIE 나 Safari 버전에서 여전히 지원하지 않는 속성에 주의하십시오 . 여기 체크 아웃 : caniuse.com/#feat=download
피에르 - 아드 비종

내가 내 기본 페이지로 $ urlRouterProvider 및 리디렉션에 대한 URL을 각도와 함께 사용하면, 내비게이션 대신 파일을 다운로드하는 모든 솔루션이있다
HardikDG

누군가가 그런 링크를 게시 할 때 항상 애용합니다.
slugmandrew 2010

22

이것은 다른 브라우저 창을 열 필요없이 자바 스크립트에서 수행 할 수 있습니다.

window.location.assign('url');

'url'을 파일 링크로 바꿉니다. 이것을 함수에 넣고 ng-click버튼에서 다운로드를 트리거해야하는 경우 호출 할 수 있습니다 .


2
다운로드 대화 창을 표시하는 대신 사이트를 PDF 문서로 대체합니다.
fdrv

감사! 매력처럼 작동합니다.
Sagi

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

위의 지시문은 iframe 생성을 범위 밖에 두었을 때 작동하지 않습니다. $ on iframe을 생성하지만 브로드 캐스트를 사용할 때 $ on 이벤트가 호출되지 않습니다
Kanagu

예 $ 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

이것은 훌륭한 대답입니다. SO의 다음 링크는 전체 작동 예를 제공합니다. stackoverflow.com/a/30889331/1625820
herrtim

7

안전하지 않아서 파일을 다운로드하지 않는 경우를 추가하고 싶습니다 : 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)}
닭고기 수프

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.