HTML:
<a href="mysite.com/uploads/asd4a4d5a.pdf" download="foo.pdf">
Las cargas obtienen un nombre de archivo único, mientras que el nombre real se mantiene en la base de datos. Quiero realizar una simple descarga de archivos. Pero el código anterior redirige a / debido a:
$routeProvider.otherwise({
redirectTo: '/',
controller: MainController
});
Lo intenté con
$scope.download = function(resource){
window.open(resource);
}
pero esto solo abre el archivo en una nueva ventana.
¿Alguna idea de cómo habilitar una descarga real para cualquier tipo de archivo?
target="_blank"
otarget="_self"
? Ver: docs.angularjs.org/guide/…Respuestas:
https://docs.angularjs.org/guide/$location#html-link-rewriting
Entonces, en su caso, debe agregar un atributo de destino como este ...
<a target="_self" href="example.com/uploads/asd4a4d5a.pdf" download="foo.pdf">
fuente
download
no es compatible con IE o Safari.También tuvimos que desarrollar una solución que incluso funcionara con API que requieran autenticación (consulte este artículo )
Usando AngularJS en pocas palabras, así es como lo hicimos:
Paso 1: cree una directiva dedicada
// 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); }); }; }] });
Paso 2: crea una plantilla
<a href="" class="btn btn-primary" ng-click="downloadPdf()">Download</a>
Paso 3: Úselo
<pdf-download url="/some/path/to/a.pdf" filename="my-awesome-pdf"></pdf-download>
Esto generará un botón azul. Al hacer clic, se descargará un PDF (Precaución: ¡el backend tiene que entregar el PDF en codificación Base64!) Y se colocará en el archivo href. El botón se vuelve verde y cambia el texto a Guardar . El usuario puede hacer clic de nuevo y se le presentará un diálogo de archivo de descarga estándar para el archivo my-awesome.pdf .
Nuestro ejemplo usa archivos PDF, pero aparentemente podría proporcionar cualquier formato binario dado que está codificado correctamente.
fuente
Si necesitas una directiva más avanzada, te recomiendo la solución que implementé, correctamente probada en Internet Explorer 11, Chrome y FireFox.
Espero que te sea de ayuda.
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>
DIRECTIVA:
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'); } } }); } } })
EN CONTROLADOR:
$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=[]; }); };
EN SERVICIO:
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 (en PRIMAVERA):
@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; }
fuente
en plantilla
<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>
en controlador
$scope.export = function(){ $window.location.href = $scope.export; };
fuente