Angularjs simple file загрузить
HTML:
<a href="mysite.com/uploads/asd4a4d5a.pdf" download="foo.pdf">
Загрузки получают уникальное имя файла, пока в базе данных хранится реальное имя. Я хочу реализовать простую загрузку файла. Но вышеприведенный код перенаправляет на/из-за:
$routeProvider.otherwise({
redirectTo: '/',
controller: MainController
});
Я пробовал с помощью
$scope.download = function(resource){
window.open(resource);
}
но это просто открывает файл в новом окне.
Любые идеи о том, как включить реальную загрузку для любого типа файла?
Ответы
Ответ 1
https://docs.angularjs.org/guide/$location#html-link-rewriting
В следующих случаях ссылки не переписываются; вместо этого браузер выполнит полную перезагрузку страницы по исходной ссылке.
-
Ссылки, содержащие целевой элемент Пример:
<a href="/ext/link?a=b" target="_self">link</a>
-
Абсолютные ссылки, которые идут в другой домен Пример:
<a href="http://angularjs.org/">link</a>
-
Ссылки, начинающиеся с '/', которые приводят к другому базовому пути, когда база определена. Пример:
<a href="/not-my-base/link">link</a>
Итак, в вашем случае вы должны добавить целевой атрибут, например...
<a target="_self" href="example.com/uploads/asd4a4d5a.pdf" download="foo.pdf">
Ответ 2
Нам также пришлось разработать решение, которое даже работало бы с API-интерфейсами, требующими аутентификации (см. в этой статье)
Использование AngularJS в двух словах вот как мы это сделали:
Шаг 1. Создайте специальную директиву
// jQuery needed, uses Bootstrap classes, adjust the path of templateUrl
app.directive('pdfDownload', function() {
return {
restrict: 'E',
templateUrl: '/path/to/pdfDownload.tpl.html',
scope: true,
link: function(scope, element, attr) {
var anchor = element.children()[0];
// When the download starts, disable the link
scope.$on('download-start', function() {
$(anchor).attr('disabled', 'disabled');
});
// When the download finishes, attach the data to the link. Enable the link and change its appearance.
scope.$on('downloaded', function(event, data) {
$(anchor).attr({
href: 'data:application/pdf;base64,' + data,
download: attr.filename
})
.removeAttr('disabled')
.text('Save')
.removeClass('btn-primary')
.addClass('btn-success');
// Also overwrite the download pdf function to do nothing.
scope.downloadPdf = function() {
};
});
},
controller: ['$scope', '$attrs', '$http', function($scope, $attrs, $http) {
$scope.downloadPdf = function() {
$scope.$emit('download-start');
$http.get($attrs.url).then(function(response) {
$scope.$emit('downloaded', response.data);
});
};
}]
});
Шаг 2. Создание шаблона
<a href="" class="btn btn-primary" ng-click="downloadPdf()">Download</a>
Шаг 3: используйте его
<pdf-download url="/some/path/to/a.pdf" filename="my-awesome-pdf"></pdf-download>
Появится синяя кнопка. При нажатии на него будет загружен PDF файл (Внимание: бэкэнд должен доставить PDF-код в кодировке Base64!) И ввести в href. Кнопка станет зеленой и переключит текст на Сохранить. Пользователь может снова щелкнуть и будет представлен стандартный диалог файла загрузки для файла my-awesome.pdf.
В нашем примере используются файлы PDF, но, судя по всему, вы можете предоставить любой двоичный формат, если он правильно закодирован.
Ответ 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 (на SPRING):
@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;
}
Ответ 4
в шаблоне
<md-button class="md-fab md-mini md-warn md-ink-ripple" ng-click="export()" aria-label="Export">
<md-icon class="material-icons" alt="Export" title="Export" aria-label="Export">
system_update_alt
</md-icon></md-button>
в контроллере
$scope.export = function(){ $window.location.href = $scope.export; };
Ответ 5
Я знаю, что это старый пост, но у меня возникли проблемы с получением любого решения для обмена стеками, работающего для автоматической загрузки с сообщением Angular.
Здесь мое решение (гибрид jquery/ Angular/php):
PHP
return array($filename,$url);
Angular Просмотр
<a target="_self" id="downloadpdf" href={{downloadurl}} download={{filename}} style="display: none"></a>
Angular Контроллер
после получения ответа с URL-адресом и именем файла:
$scope.downloadurl=data[1];
$scope.filename=data[0];
setTimeout(function () {
$('#downloadpdf')[0].click();
}, 1000);
Я помещал это на задержку в 1 секунду, чтобы дать время для заполнения значений, потому что иногда он выполнялся слишком быстро.
Надеюсь, что это поможет!