I'm calling an api and returning a byte array, name, document type and mime type of a file and trying to add Javascript to download this file.
I've all the code wired in and it downloads a file but the file is empty. I'm using the following code:
result.success(function (data, status, headers, config) {
var arr = data.Document;
var byteArray = new Uint8Array(arr);
var a = window.document.createElement('a');
a.href = window.URL.createObjectURL(new Blob([byteArray], { type: data.MimeType}));
a.download = agreementId+data.DocType;
// Append anchor to body.
document.body.appendChild(a);
a.click();
// Remove anchor from body
document.body.removeChild(a);
});
I've tried the same code without the conversion to Uint8Array but this just opens a document with the binary data in it, close but not quite there. Eg I get a download of a word document that contains:
0M8R4KGxGuEAAAAAAAAAAAAAAAAAAAAAPgADAP7/CQAGAAAAAAAAAAAAAAABAAAATwAAAAAAAAAAEAAAUQAAAAEAAAD+////AAAAAE4AAAD////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////spcEAJ2AJBAAA
ect
Related
I am trying to create a button that triggers a download of a JSON file. (And please i don't want to use any libraries to achieve this). Thank you.
import Data from '../Data';
let data = Data;
<Button>Download</Button>
Triggering browser download from front-end is not reliable.
What you should do is, create an endpoint that when called, will provide the correct response headers, thus triggering the browser download.
Front-end code can only do so much. The 'download' attribute for example, might just open the file in a new tab depending on the browser.
Take a look at this solution: How to create a file in memory for user to download, but not through server? I have rewritten their code a bit, but basically for your case, you'd want...
// Set globals
var mimetype = 'application/json';
var filename = 'yourfile.json';
// Create Dummy A Element
var a = window.document.createElement('a');
// createObjectURL for local data as a Blob type
a.href = window.URL.createObjectURL(new Blob([data], {
encoding: "UTF-8",
type: mimetype + ";charset=UTF-8",
}));
a.download = filename;
// Download file and remove dummy element
document.body.appendChild(a);
a.click();
a.remove();
You would need to create a file using your data and then create a downloadable link
and append it in whichever part of your application you would like to.
const fileName = "file";
const json = JSON.stringify(data);
const blob = new Blob([json],{type:'application/json'});
const href = await URL.createObjectURL(blob); // Create a downloadable link
const link = document.createElement('a');
link.href = href;
link.download = fileName + ".json";
document.body.appendChild(link); // This can any part of your website
link.click();
document.body.removeChild(link);
An Axios request to server response the content of a PDF as a binary string.
export const fetchPDFfile = async (id: string): Promise<string> => {
const { data } = await http.get<string>(`${baseUrl}/${id}.pdf`);
return data;
};
The response in Chrome devtools and also console logging the data is like:
%PDF-1.4
%âãÏÓ
2 0 obj <</ColorSpa ......
..........
startxref
10991
%%EOF
is defining string as the expected type of Axios response body, correct? or it should be (cast to) Blob?
Now I want to download this as a PDF file in the client-side. There are plenty of questions regarding this but none worked for me and also none had a clear answer.
So what I did so far was (in a React component):
const data = await fetchPDFfile(props.id);
const blob = new Blob([data], { type: 'application/pdf' });
const href = window.URL.createObjectURL(blob);
const theLink = document.createElement('a');
theLink.href = href;
theLink.download = props.id + '.pdf';
document.body.appendChild(theLink);
theLink.click();
document.body.removeChild(theLink);
This downloads a PDF file with 3 blank pages. The number of pages is correct the original doc should bee 3 pages. But I see the white paper.
const href = window.URL.createObjectURL(data); // istead of blob throw Error.
How should I convert and download this PDF file? In general, is the process above needed, or should I directly download it from the server? (something like what cordova-plugin-file-transfer does)
Scenario
You want the file to be downloaded when the user clicks the link.
Solution 1-
Directly put the link in <a> tag.
Cons- Error message can not be shown on the screen if something went wrong.
So it leads to the next solution.
Solution 2-
Hit the URL as an API and download the file if you get the success message.
For this, I use File-server.js
**Don't forget to set the {responseType: 'blob'}, while making the request
http.get<string>(`${baseUrl}/${id}.pdf`, {responseType: 'blob'})
as we don't want the response with Content-Type: application/json
sample code:
import FileSaver from 'file-saver';
downloadPdf() {
var blob = new Blob([data], {type: "application/pdf"});
FileSaver.saveAs(blob, "filename");
}
Firstly use Blob as generic argument for Promise.
I will use fetch API as it can be tested quite easily.
fetch('https://www.jianjunchen.com/papers/CORS-USESEC18.slides.pdf').then(x => x.blob()).then(b => console.log(b.type))
This will log "application/pdf" it the file is trully pdf.
If you got a blob that is not PDF and you will re-wrap it to Blob with pdf type you might break the data. If you got trully a string and you convert it to Blob with pdf type the file will be broken as the PDF would be invalid.
If you want to know if b is trully a blob just console.log(b instanceof Blob) and it should say true. If you have recieved trully a blob you do not have to create new one as you did in new Blob([data]).
This example works just fine:
fetch('https://www.jianjunchen.com/papers/CORS-USESEC18.slides.pdf').then(x => x.blob()).then(b => {
const url = window.URL.createObjectURL(b);
var a = document.createElement("a");
document.body.appendChild(a);
a.style = "display: none";
a.href = url;
a.download = "a.pdf";
a.click();
window.URL.revokeObjectURL(url);
})
Sorry for broken code style but I was unable to paste it properly.
I am having some text like below to be saved in a downloadable doc format using javascript blob.
<p style='font-size:18px'>Hello</p>
Once the download happens I want the doc to show just show formatted 'Hello' without any html tags. In ubuntu this works very well.
But when I open the same doc in windows or google docs, I still see html tags.
Is there a way where I can do this formatting at Blob level itself. Below is the way Iam creating blob object.
var file = new Blob([val], {type: "octet/stream"});
Appreciate your help on this.
Try adjusting type of Blob to "text/html" , using URL.objectCreateURL() as file object reference for download
var val = "<div>abc</div>";
var file = new Blob([val], {
type: "text/html"
});
// file object reference
var download = URL.createObjectURL(file);
var a = document.createElement("a");
a.href = download;
a.download = "file-" + new Date().getTime();
document.body.appendChild(a);
a.click()
During implementation of file transfer use case through WebRTC protocol, i am recieving data from queue at reciever end in some variables but unable to use that. Through some digging, i came to know that it can be done using Blob,
code snippet that i used :
var data=reciever.dequeue();
if(data)
{ var blob = new Blob(_base64ToArrayBuffer(data), {type: 'text/plain'});
// need to know how to proceed now?
}
file is need to be saved in local system.Thanks in advance.
You can create a temp anchor element element and append it to document.body, trigger click event. Done.
Here is the demo code:
var url = objectURL = URL.createObjectURL(blob); //your blob object here
var anchor = document.createElement("a");
anchor.href = url;
anchor.download = "YourFileName";
anchor.click(); //This will trigger browser download event.
Here is document about blob to URL.
Here is the blob document.
Hope this works. : )
I'm trying to implement the download of a file through angular.js
The file comes from the server in binary format, the content type is application/octet-stream
The download is a GET using $resource. Looking at the parameter passed to the callback (called content below), it's an object containing the byte array and also a list of properties for $resource.
Tried several ways to serve the file, but without success.
First of them:
...
var a = document.createElement('a');
a.href = "data:attachment/zip," + content;
a.download = zipName;
a.click();
In this case, the content of the zip file is [object Object]
I tried extracting the array from the object and joining everything into a string variable. The zip file in this case is way larger than the normal size. I had to set isArray: true in the service that calls $resource, otherwise there was no way to extract the byte content from the response object.
Here is how I did it:
var str = '';
for (var i = 0; i < content.length; i++) {
str += content[i][0];
}
...
var a = document.createElement('a');
a.href = "data:attachment/zip," + str;
a.download = zipName;
a.click();
Worth mentioning that calling encodeURI on str increments drastically the size of the downloaded zip, but the archive remains invalid.
I also tried creating a Blob from the str and setting the content type to application/octet-stream, without any luck.
var blob = new Blob([str], {'type':"application/octet-stream"});
a.href = window.URL.createObjectURL(blob);
...
Don't know what I'm missing here, but it looks rather a problem of getting the right format for the byte array content and setting the correct href before simulating the click for downloading.
Help is appreciated.
Thanks
I just found your post and fixed an answer using what you enlist.
First you have to ensure that your angular $http request includes, like the following get example (include responseType: 'arraybuffer')
$http.get('/downloadZip', {
params: {
file: encodeURIComponent(filepath)
},
responseType: 'arraybuffer'
//your code
Second on your success or promise handler you should change your window.URL.createObjectURL(blob) to URL.createObjectURL(blob). Implementing something similar to the following:
var a = document.createElement('a');
var blob = new Blob([data], {'type':"application/octet-stream"});
a.href = URL.createObjectURL(blob);
a.download = "filename.zip";
a.click();
With these you are creating a new anchor element and simulating to opening it. With a correct Blob creation since the request had been modified correctly.
Angular is no needed.
var zip_file_path = "" //put inside "" your server path with file.zip
var zip_file_name = "" //put inside "" file name or something
var a = document.createElement("a");
document.body.appendChild(a);
a.style = "display: none";
a.href = zip_file_path;
a.download = zip_file_name;
a.click();
document.body.removeChild(a);
In case anyone is still on AngularJS (like me) and wants to do this, I took David's answer and made it work with the angular $resource instead of using the lower level $http directly. If you use $resource, this should help you:
var myReportingResource = $resource(baseURL + '/mypath/:command', {},{
getExportZip: {
method: 'GET',
params: {
command: 'exportzip'
},
responseType: 'arraybuffer',
// don't try to convert the zip to JSON
// instead take the data that comes back and put it in an object under a content key
transformResponse: function(data){
return {content: data};
}
}
});
// call the resource like this
myReportingResource.getExportZip(yourParams).$promise.then(function(zipData){
// create a anchor element, stick the zip data in it, and click it to download
var anchor = angular.element('<a/>');
anchor.attr({
href: URL.createObjectURL(new Blob([zipData.content], {'type':'application/octet-stream'})),
download: 'myfilename.zip'
})[0].click();
});
You need the transformResponse bit because otherwise AngularJS will convert your response to JSON- which is wrong with binary data. This is why later you use zipData.content to pass the data into the Blob. You can get rid of the content part, it's there for simplicity with my error handling code.
This works in Chrome and Safari as of May 2019. Didn't test anywhere else.