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.