La descarga simple de archivos de Angularjs hace que el enrutador redirija

HTML:

 

Las subidas obtienen un nombre de archivo único mientras 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?

https://docs.angularjs.org/guide/$location#html-link-rewriting

En casos como el siguiente, los enlaces no se reescriben; en cambio, el navegador realizará una recarga de página completa al enlace original.

  • Enlaces que contienen elemento objective Ejemplo:
    link

  • Enlaces absolutos que van a un dominio diferente Ejemplo:
    link

  • Enlaces que comienzan con ‘/’ que conducen a una ruta base diferente cuando se define base Ejemplo:
    link

Entonces, en tu caso, deberías agregar un atributo objective como ese …

  

También tuvimos que desarrollar una solución que incluso funcionaría con las API que requieren autenticación (ver este artículo )

Usando AngularJS en pocas palabras aquí es cómo lo hicimos:

Paso 1: crea 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

 Download 

Paso 3: usarlo

  

Esto generará un botón azul. Al hacer clic, se descargará un PDF (¡Atención: el servidor debe entregar el PDF en la encoding Base64!) Y colocarlo en el href. El botón se pone 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.

Si necesita una directiva más avanzada, recomiendo la solución que implementé, probada correctamente en Internet Explorer 11, Chrome y FireFox.

Espero que sea útil.

HTML:

  

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('');//create a new  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  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 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; } 

en plantilla

   system_update_alt  

en el controlador

  $scope.export = function(){ $window.location.href = $scope.export; }; 

Sé que esta es una publicación anterior, pero tuve problemas para obtener una solución en el intercambio de stack para una descarga automática con una publicación angular.

Aquí está mi solución (Un híbrido de jquery / Angular / php):

PHP

  return array($filename,$url); 

Vista angular

   

Controlador Angular

una vez que la respuesta se recibe con la url y el nombre del archivo:

  $scope.downloadurl=data[1]; $scope.filename=data[0]; setTimeout(function () { $('#downloadpdf')[0].click(); }, 1000); 

Puse esto en un retraso de 1 segundo para dar tiempo a que los valores se rellenaran porque a veces se ejecutaba demasiado rápido.

¡Espero eso ayude!