Как вы подаете файл для загрузки с помощью AngularJS или Javascript?


96

У меня есть текст в скрытом текстовом поле. При нажатии кнопки я хотел бы, чтобы текст предлагался для загрузки в виде .txtфайла. Возможно ли это с помощью AngularJS или Javascript?


1
Какие браузеры вы поддерживаете? Это можно решить некоторыми творческими способами (например, data-uris, blobs, API истории браузера и т. Д.), Но это действительно зависит.
Бенджамин Грюнбаум

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вместо этого.
Густаво Штраубе

7
Я заметил, что тогда тег привязки имеет префикс unsafe. Чтобы обойти это, вам нужно добавить 'blob' в белый список в вашем app.js, используя $ 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

Нравится это решение! При получении данных с сервера, например, при использовании, $http.get(...)убедитесь, что вы установили, responseType:'arraybuffer'как описано здесь: stackoverflow.com/questions/21628378/…
Тим Бют 01

Работает в 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
Остерегайтесь downloadатрибута, который по-прежнему не поддерживается ни в IE, ни в версии Safari. Проверьте это здесь: caniuse.com/#feat=download
Пьер-Адриан Бюиссон,

Когда я использую его с angular, он берет URL-адрес на $ urlRouterProvider и перенаправляет на мою страницу по умолчанию, есть ли какое-либо решение для загрузки файла вместо навигации
HardikDG

Мне всегда снисходительно, когда кто-то публикует такую ​​ссылку.
slugmandrew

22

Это можно сделать с помощью javascript без необходимости открывать другое окно браузера.

window.location.assign('url');

Замените url ссылкой на ваш файл. Вы можете поместить это в функцию и вызвать ее, ng-clickесли вам нужно запустить загрузку с помощью кнопки.


2
Вместо этого он заменяет сайт документом в формате PDF для отображения диалогового окна загрузки.
fdrv 06

Спасибо! Работает как шарм.
Sagi

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
Фрагмент кода будет большим подспорьем.
Sudhir N

Приведенная выше директива не работает для меня, когда я помещаю создание iframe вне области видимости. $
On

Да $ scope. $ Broadcast работает только с детьми. Если возможно, вы можете поместить директиву в область верхнего уровня.
Кетан

12

Вы можете установить location.hrefв данных URI , содержащий данные , которые вы хотите , чтобы позволить загрузку пользователя. Помимо этого, я не думаю, что есть способ сделать это с помощью только JavaScript.


Это отлично работает для меня и было намного чище, чем все другие вещи, которые мы пробовали, или ИМХО, сложные подходы, рекомендованные выше. 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.config (function ($ compileProvider) {

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

5

Если у вас есть доступ к серверу, рассмотрите возможность установки заголовков, как указано в этом более общем вопросе .

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

Читая комментарии к этому ответу, рекомендуется использовать более конкретный Content-Type, чем octet-stream.


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

НАЗАД (ВЕСНОЙ):

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

Спасибо, это действительно сработало для меня, особенно потому, что мне нужно было передавать большие файлы.
Маркос Пауло SUS

3

Это сработало для меня в angular:

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

Если у вас есть строка, которую вы хотите загрузить, просто измените fileURL наdata:text/plain;base64,${btoa(theStringGoesHere)}
Chicken Soup

2

Мне не нужен статический URL. У меня есть AjaxFactory для выполнения всех операций ajax. Я получаю URL-адрес с завода и привязываю его следующим образом.

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

Спасибо @AhlemMustapha

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.