Force download of 'data:text/plain' URL - file

I was wondering whether it is possible to force a browser (at least Chrome) to download a data:text/plain URL.
Chrome does download binary URLs (e.g. data:application/zip;base64,...), but it does not download files that can be viewed inside the browser (such as text files).
What I already tried with no luck so far is this:
data:text/plain;content-disposition=attachment;filename=test.txt;...
But it seems like I cannot add headers like this.
Is there any way to make Chrome download a data:text/plain,... URL?

As of now, it has been made possible to use <a download> in Chrome. Using dispatchEvent, you can download any string as file (even with a custom filename) whenever you want. Here's a utility function to use it:
var downloadFile = function(filename, content) {
var blob = new Blob([content]);
var evt = document.createEvent("HTMLEvents");
evt.initEvent("click");
$("<a>", {
download: filename,
href: webkitURL.createObjectURL(blob)
}).get(0).dispatchEvent(evt);
};
Usage:
downloadFile("foo.txt", "bar");
It uses jQuery and the webkit prefix, but both can be avoided.

Try this:
<a download="file_downloaded_via_data_URL.txt"
href="data:text/plain;base64,SGVsbG8sIHdvcmxkISBJJ20gZG93bmxvYWRlZCB2aWEgImRhdGE6dGV4dC9wbGFpbjsuLi4iIFVSTCB1c2luZyA8YSBkb3dubG9hZD0iZmlsZV9uYW1lIi4uLj4uDQpNeSBiaXJ0aHBsYWNlOiBodHRwOi8vc3RhY2tvdmVyZmxvdy5jb20vcXVlc3Rpb25zLzY0Njg1MTcvDQoNCk1vcmUgYWJvdXQ6DQpodHRwOi8vd3d3LnczLm9yZy9UUi9odG1sL2xpbmtzLmh0bWwjYXR0ci1oeXBlcmxpbmstZG93bmxvYWQNCmh0dHA6Ly93d3cudzMub3JnL1RSL2h0bWwvbGlua3MuaHRtbCNkb3dubG9hZGluZy1yZXNvdXJjZXMNCg0KQnJvd3NlciBzdXBwb3J0OiBodHRwOi8vY2FuaXVzZS5jb20vZG93bmxvYWQ=">
Download text file
</a>
It uses HTML5 attribute download="filename.ext". (no JS needed:)
More about:
http://www.w3.org/TR/html/links.html#downloading-resources
Browser support can be checked at http://caniuse.com/download
(As for now, 2013, no IE nor Safari support)
I think, you can make a fallback for not-supporting browsers: use JS to change value of href="..." to the URL of your server script (which will return the file contents with appropriate HTTP header Content-disposition: attachment;filename=filename.txt).

Here is a pure Javascript solution for creating a text blob and download as text file
var fileContent = 'This is sample text file';
var fileName = 'sampleFile.txt';
const blob = new Blob([fileContent], { type: 'text/plain' });
const a = document.createElement('a');
a.setAttribute('download', fileName);
a.setAttribute('href', window.URL.createObjectURL(blob));
a.click();

What I did was sending the data to a server, which sends them back with the following HTTP header:
Content-disposition: attachment;filename=test.txt
I don't like this, but it works rather well.

This works as hell ...
<div class="tags-style-one dragme" draggable="true" data-transfer="33343">some value is 33343</div>
<script type="text/javascript">
(function ($) {
$(document).ready(function () {
$('.dragme').on("dragstart",function(evt) {
evt.originalEvent
.dataTransfer
.setData(
"text/plain",
$(this).data('transfer').toString()
);
});
})(jQuery);
</script>

Related

How to call function from a third-party library dynamically loaded in React

We're testing out the ZenDesk web widget, and I have some code that dynamically imports the scripts based on environment, with the following code in the base html file.
<script type='text/javascript'>
if (window.location.host === 'localhost') {
var src = "https://static.zdassets.com/ekr/snippet.js?key=<our key>";
var newScript = document.createElement("script");
newScript.type = "text/javascript";
newScript.id = "ze-snippet";
newScript.setAttribute("async", "true");
newScript.setAttribute("src", src);
document.body.appendChild(newScript);
}
</script>
The help function is dynamic based on URL, but being an SPA, I need to manually call the update function each time the URL changes. How do I go about accessing a function within a third-party library that's being loaded dynamically?
The function that needs to be called on route change is as follows:
zE('webWidget', 'helpCenter:setSuggestions', {
url: true
});
My app obviously has no idea what zE is, so that won't work. Is there a better way to do this?

How to download a text file based on a generated String using AngularJS?

I'm trying to get AngularJS to trigger a file download when a user clicks on a button.
The file that should download has to contain data that is generated during the script execution, so the text file's content should be built from a basic string in AngularJS.
How do I implement this?
Here is some mockup code on how I imagine this would work:
var fileContent = 'foobar';
$scope.download = function() {
filedownload.run(fileContent, 'filename.txt');
}
In order to achieve this you have to create an a tag in your HTML:
<a download="content.txt" ng-href="{{ url }}">download</a>
Controller:
var content = 'file content for example';
var blob = new Blob([ content ], { type : 'text/plain' });
$scope.url = (window.URL || window.webkitURL).createObjectURL( blob );
And to enable the URL:
app = angular.module(...);
app.config(['$compileProvider',
function ($compileProvider) {
$compileProvider.aHrefSanitizationWhitelist(/^\s*(https?|ftp|mailto|tel|file|blob):/);
}]);
Source:
How do you serve a file for download with AngularJS or Javascript?
In simple cases, you can create a link with a Data URI:
var fileContent = 'foobar';
$scope.download = 'data:text/plain;base64,' + btoa(fileContent);
And then use it in your HTML template:
click here to download
You may need to adapt the MIME type, depending on your string.

Saving/downloading binary (buffer?) as a pdf

User uploads the pdf file which gets saved to mongo as a binary, files are small in size (<1mb) so I am not using GridFS.
How to download the pdf back?
Here is what I have tried:
I am extracting the binary from mongo and sending it back to the user. I am using Hapi, sending it back goes simply as
res(binaryMongoPDF).code(200);
I am receiving same data I have store in mongo on the client. According to what I have read I should convert the binary to blob:
var blob = new Blob([data], { type: 'application/pdf' });
I have tried with and without setting responseType to arraybuffer:
$http.get(API_URL + "/cv/me", {responseType:'arraybuffer'})
and then just let user download it, I am simplifying that with Angular FileSave, but I have also tried with vanilla a tag creation approach:
FileSaver.saveAs(r, 'text.pdf');
The file I am getting back can't be opened as a pdf.
Something I have observed is that binary file I am saving in mongo has size 73262, but the blob has size 97426. I have no idea if this is normal or not.
If the server returns the file as a data url:
data:application/octet-stream;base64,iVBORw0KGgoAAAANSUhEUgA
Use this directive:
angular.module("myApp").directive("xdHref", function() {
return function linkFn (scope, elem, attrs) {
scope.$watch(attrs.xdHref, function(newVal) {
newVal && elem.attr("href", newVal);
});
};
});
To set the href attribute of an <a> tag with the data:
<a download="data_{{files[0].name}}" xd-href="data">
<button>Download data</button>
</a>
The DEMO on PLNKR

get source and name of selected file with angularjs

Is there a way to get name, path and size of selected file in input field using angularJS,
before uploading it?
<input type="file" ng-model="fileContent" on-read-file="showContent($fileContent)" />
$scope.showContent = function($fileContent){
$scope.content = $fileContent;
};
Can anyone help to solve this please?
The HTML5 File API will give you a File object for each file that you're attempting to upload. This File object will have a size and name property which will give you the file size in bytes and the name of the file.
There's no property for the physical path to the file on the users machine, though.
You can read more about this on MDN: https://developer.mozilla.org/en-US/docs/Using_files_from_web_applications
More information on the File object here: https://developer.mozilla.org/en-US/docs/Web/API/File
Here's a working example: http://jsfiddle.net/fmeLz9cd/
Given an input of type file with an id fileSelected, here's an example of accessing the properties through the File API:
$('#fileSelected').on('change', function (evt) {
var files = $(evt.currentTarget).get(0).files;
if(files.length > 0) {
$('#fileName').text(files[0].name);
$('#fileSize').text(files[0].size);
$('#filePath').text($('#fileSelected').val());
}
});
Update
Since you've requested an AngularJS specific example, here's the same code working in an angular app:
http://jsfiddle.net/vyc6jq84/1/
<div ng-app="fileDemo">
<input type="file" fd-input />
</div>
var app = angular.module('fileDemo', []);
app.directive('fdInput', [function () {
return {
link: function (scope, element, attrs) {
element.on('change', function (evt) {
var files = evt.target.files;
console.log(files[0].name);
console.log(files[0].size);
});
}
}
}]);
You cannot, unless the server helps. Angular is running in your browser, and cannot read the filesystem of the server or of the browser's computer. If you want to get a file, you need the server to implement something that will do so.
Now, if it is a static file, and already is served up by the server, then you could read it via $http.
$http.get(filename).success(function(data){
// data contains the file content
});
But it may be interpreted based on the file type, etc. And this entirely presumes the file is already being served by the server.

Trigger click on element dynamically created by AngularJS

I'm using AngularJS to create a new tag in order to download a csv file. Below the code I use to trigger the download. The download starts on Chrome but not in Firefox. Do you have any clue why this happens?
var element = angular.element('<a/>');
element.attr({
href: exportedString,
target: '_self',
download: 'test.csv'
})[0].click();
EDIT: Firefox needs an existent DOM
JS:
var linkElem = $("#link");
var element = angular.element(linkElem);
HTML:
<a ng-hide=true id="link"></a>
EDIT 2: On Chrome, the downloaded file name is "download" and not the passed value ("test.csv" in this case). Any suggestions?
Here there is also a plunker
This is a bug in Chrome 35 reported in issue #377860.
Follow this answer for more details
I updated your plunker solution.
Basically you need to use it like follow:
var element = document.createElement('a');
var blob = new Blob([$scope.exportContent], {
type: 'text/csv'
});
var url = URL.createObjectURL(blob);
element.href = url;
element.setAttribute('download', 'test.csv');
document.body.appendChild(element); //Append the element to work in firefox
element.click();
To get both Chrome & FF to work, I actually found that I had to first check to see if element[0] was undefined (which it was in Chrome but not FF):
var link = $("#reportDownloadLink");
var element = angular.element(link)
.attr('href', dataUrl)
.attr('download', data.FileDownloadName)
.attr('target', '_blank');
(element[0] || element).click();

Resources