Download/Save file in react js - javascript

How can i save the response from api which gives me excel file with data and name ?
I have below api which gives me the excel file and i have to save it at default location as is.
https://mydomain.dev.com/export
I have gone through the multiple articles on the web but everywhere its explained to save the data as excel file at client side which is not the my case. For me, file type and name is already decided at server side and i have to just save as is.
Thanks a lot in advance

Here's how I usually handle this:
I start out by fetching the file and then use downloadjs to download the blob
async downloadFile() {
const res = await fetch("https://mydomain.dev.com/export");
const blob = res.blob();
// from downloadjs it will download your file
download(blob, "file.xlsx", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
}

I always use this script to do this:
function downloadFile(absoluteUrl) {
var link = document.createElement('a');
link.href = absoluteUrl;
link.download = 'true';
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
delete link;
};
So just :
downloadFile("https://mydomain.dev.com/export");
It is working, but i hope that there is better solution.

Related

Flask send_file inline not working as expected

Generating a PDF report in Flask and sending the file to the client using:
send_file(file,as_attachement=False)
On the React JS end I have a function the handles the PDF file: Using Axios:
const receiveFile = (data) => {
if (data.data) {
let url = window.URL.createObjectURL(new Blob([data.data]));
let link = document.createElement("a");
link.href = url
link.setAttribute("download", data.filename)
document.body.appendChild(link)
link.click()
document.body.removeChild(link)
}
}
The file gets sent without issue and the receiveFile received the data properly; however, my browser is set to open PDF files. Instead I am being asked to download it. How do I fix the code so the browser displays the PDF when it is received.

Download multiple files via Axios and .zip them

I am trying to expose a .zip in VueJS containing multiple files that are stored in a remote server.
I have tried at least with just one .csv file: the download works, but opening the archive fails because the .zip is recognised as invalid.
What I have tried to do is, this following this previous issue:
try {
const response = await axios.get(download_url, {
responseType:'blob'
});
const url = window.URL.createObjectURL(new Blob([response.data));
const link = document.createElement("a");
link.href = url;
link.setAttribute("download", "filename.zip");
document.body.appendChild(link);
link.click();
} catch (error) {
console.log(error);
}
That allows me to download the .zip, but again, it is invalid and I cannot open it.
Then, I would like to be able to do it with multiple "download_urls", i.e. with multiple files in the same .zip, but for now I would be happy to succeed at least with one file!
Thank you in advance with your help.
Let the link () be directly what you are getting from axios (axios.get(url))
To download multiple file in one zip you could let the server pack them and provide public link to download (we can elaborate on this if you need to)
Again use that public link from the server to download the zip
Use download_url and put it in a

Create and Download PDF file from binary string with JS/TS

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.

React:write to json file or export/download [no server]

I got really confused with file I/O in JS/TS. most examples I see works with DOM and has browser-based solutions.
Also, I did not understand how to make fs work, it seems to need a webpack config, where I use CRA and do not want to eject.
in a React component I want to fetch some data from a server then save them as a JSON file in the project folder (the same path, root, public folder, no matter) or directly download (no button needed).
//data type just in case
inteface IAllData{ name:string; allData:IData[];}
so after fetching some data want to save them to name.json
public componentDidMount(){
this.fetchData().then(()=>this.saveData())
}
public async fetchData(){/* sets data in state*/}
public saveData(){
const {myData}=this.state;
const fileName=myData.name;
const json=JSON.stringify(myData);
const blob=new Blob([json],{type:'application/json'})
/* How to write/download this blob as a file? */
}
here trying window.navigator.msSaveOrOpenBlob(blob, 'export.json'); did not work
note: I know it has security risks, it is not for production. save the file in the project folder is preferred but a download is totally ok.
I had a blob containing data and I had found a solution on stackoverflow and manipulated a bit, and succeded to download as a xlsx file. I am adding my code below, it might help you, too.
const blob = await res.blob(); // blob just as yours
const href = await URL.createObjectURL(blob);
const link = document.createElement('a');
link.href = href;
link.download = "file.xlsx";
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
EDIT: You can use the function below, but be sure to switch out fileName and myData from this.state to something that will work in your application.
const downloadFile = () => {
const { myData } = this.state; // I am assuming that "this.state.myData"
// is an object and I wrote it to file as
// json
// create file in browser
const fileName = "my-file";
const json = JSON.stringify(myData, null, 2);
const blob = new Blob([json], { type: "application/json" });
const href = URL.createObjectURL(blob);
// create "a" HTLM element with href to file
const link = document.createElement("a");
link.href = href;
link.download = fileName + ".json";
document.body.appendChild(link);
link.click();
// clean up "a" element & remove ObjectURL
document.body.removeChild(link);
URL.revokeObjectURL(href);
}
More documentation for URL.createObjectURL is available on MDN. It's critical to release the object with URL.revokeObjectURL to prevent a memory leak. In the function above, since we've already downloaded the file, we can immediately revoke the object.
Each time you call createObjectURL(), a new object URL is created, even if you've already created one for the same object. Each of these must be released by calling URL.revokeObjectURL() when you no longer need them.
Browsers will release object URLs automatically when the document is unloaded; however, for optimal performance and memory usage, if there are safe times when you can explicitly unload them, you should do so.
For the ones like me here that are looking for an easier solution when you already have your JSON as a variable:
<button
href={`data:text/json;charset=utf-8,${encodeURIComponent(
JSON.stringify(YOURJSON)
)}`}
download="filename.json"
>
{`Download Json`}
</button>
<button
type="button"
href={`data:text/json;charset=utf-8,${encodeURIComponent(
JSON.stringify(YOURJSON)
)}`}
download="filename.json"
>
{`Download Json`}
</button>
if you are using the Loic V method just ad the type for the button on the button element and should work just fine.

Download a file from a server with JavaScript / Typescript

I have a problem when I try to download a file stored on a server. I make a call and get a right response in which I have all the information I need, in the headers I have the content type and the file name, and I have the file body in the response body.
What I want to do is to simply make a download process, so I tried to do so, data being the http call response :
// Get headers info
let headers = data.headers
let contentType = headers.get("Content-Type")
let name = headers.get("name")
// Initialize Blob
let blob = new Blob([data.text()], {type: contentType})
// Make the download process
let a = window.document.createElement("a")
a.href = window.URL.createObjectURL(blob)
a.download = name
document.body.appendChild(a)
a.click()
document.body.removeChild(a)
For a text file, it's working as it's an easy format, but for like a picture or a PDF file it makes download a file of the right name and type, but they can't be well read.
Has anyone an idea ? Thanks !
Found a way to do it using the way described below by simulating an tag with href and download parameters :)
how to set a file name using window.open

Categories