J'ai du texte dans une textarea cachée. Quand un bouton est cliqué, j'aimerais que le texte proposé au téléchargement soit un fichier .txt
. Est-ce possible d'utiliser AngularJS ou Javascript?
Vous pouvez faire quelque chose comme ceci en utilisant Blob
.
<a download="content.txt" ng-href="{{ url }}">download</a>
dans votre contrôleur:
var content = 'file content for example';
var blob = new Blob([ content ], { type : 'text/plain' });
$scope.url = (window.URL || window.webkitURL).createObjectURL( blob );
afin d'activer l'URL:
app = angular.module(...);
app.config(['$compileProvider',
function ($compileProvider) {
$compileProvider.aHrefSanitizationWhitelist(/^\s*(https?|ftp|mailto|tel|file|blob):/);
}]);
S'il vous plaît noter que
Chaque fois que vous appelez createObjectURL (), une nouvelle URL d'objet est créée, même si vous en avez déjà créée une pour le même objet. Chacun de ceux-ci doit être libéré en appelant URL.revokeObjectURL () lorsque vous n'en avez plus besoin. Les navigateurs les publient automatiquement lorsque le document est déchargé. Toutefois, pour optimiser les performances et l'utilisation de la mémoire, vous devez le faire s'il existe des moments sûrs où vous pouvez les décharger explicitement.
Source: MDN
Essaye ça
<a target="_self" href="mysite.com/uploads/ahlem.pdf" download="foo.pdf">
et visitez ce site cela pourrait vous être utile :)
Cela peut être fait en javascript sans avoir à ouvrir une autre fenêtre de navigateur.
window.location.assign('url');
Remplacez "URL" par le lien vers votre fichier. Vous pouvez mettre ceci dans une fonction et l'appeler avec ng-click
si vous devez déclencher le téléchargement depuis un bouton.
Dans notre projet actuel au travail, nous avions un iFrame invisible et je devais fournir l'URL du fichier à l'iFrame pour obtenir une boîte de dialogue de téléchargement. Lorsque vous cliquez sur le bouton, le contrôleur génère l’URL dynamique et déclenche un événement $ scope dans lequel figure une liste directive
personnalisée que j’ai écrite. La directive ajoutera un iFrame au corps s'il n'existe pas déjà et définit l'attribut url dessus.
EDIT: Ajouter une directive
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;
});
Cette directive répond à un événement du contrôleur appelé downloadFile
donc dans votre contrôleur vous faites
$scope.$broadcast("downloadFile", url);
Vous pouvez définir location.href
sur un data URI contenant les données que vous souhaitez laisser l'utilisateur télécharger. En plus de cela, je ne pense pas qu'il soit possible de le faire avec du JavaScript uniquement.
Voudrais juste ajouter que s'il ne télécharge pas le fichier pour des raisons dangereuses: blob: null ... lorsque vous passez le curseur de la souris sur le bouton de téléchargement, vous devez le nettoyer. Par exemple,
var app = angular.module ('app', []);
app.config (function ($ compileProvider) {
$compileProvider.aHrefSanitizationWhitelist(/^\s*(|blob|):/);
J'avais le même problème et passais de nombreuses heures à trouver différentes solutions, et maintenant, je rejoins tous les commentaires de ce post.
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:
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');
}
}
});
}
}
})
DANS LE CONTROLEUR:
$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 SERVICE:
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 (sur PRINTEMPS):
@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;
}
Si vous avez accès à sur le serveur, définissez les en-têtes comme a répondu à cette question plus générale .
Content-Type: application/octet-stream
Content-Disposition: attachment;filename=\"filename.xxx\"
En lisant les commentaires sur cette réponse, il est conseillé d’utiliser un type de contenu plus spécifique que octet-stream.
Je ne voulais pas d'URL statique. J'ai AjaxFactory pour faire toutes les opérations ajax. Je reçois l'URL de l'usine et la lie comme suit.
<a target="_self" href="{{ file.downloadUrl + '/' + order.OrderId + '/' + fileName }}" download="{{fileName}}">{{fileName}}</a>
Merci @AhlemMustapha
Cela a fonctionné pour moi en angulaire:
var a = document.createElement("a");
a.href = 'fileURL';
a.download = 'fileName';
a.click();