I am trying to download a server side generated pdf file in client, which i get with axios and save it in redux and using FileSaver to download it.
const getTicketPdf = ({ userID, ticketID }) =>
requestApi(`/users/${userID}/tickets/${ticketID}/pdf`, {
method: 'get',
});
requestApi gets me all neccessary headers so that i can download the file.
the data is then stored in redux like this:
data: "%PDF-1.4\n3 0 obj\n<</Type /Page\n/Parent 1 0 R\n/MediaBox [0 0 595.00 842.00]\n/Resources 2 0 R\n/Contents 4 0 R>>\nendobj\n4 0 obj\n<</Filter /FlateDecode /Length 64>>\nstream\nx�3R��2�35W(�*T0P�R0T(\u0007�Y#�\u000e��#Q…"
i call it in render with:
<div>
<button onClick={ () => this.getPdf(ticket) }>PDF</button>
</div>
getPdf = ticket => {
const blob = new Blob([ticket]);
FileSaver.saveAs(blob, 'Ticket.pdf');
}
I am always getting the following error:
TypeError: Cannot read property 'saveAs' of undefined
i tried also to set
responseType: 'blob'
but this doesn't help either.
Next thing I testet was with react-pdf library, where I managed to display pdf in Component, but i cant print it. User should only habe to save it and then print it locally (or at least show it in separate tab as PDF, which i tried with window.open() as base64 encoded string).
How can I download a server side generated PDF otherwise? Are there any better ways?
Unfortunately I have to set HTTP Headers in order to get that file.
Thanks in advance.
The error stems from the fact that there is no FileSaver object (or rather, it's non-standard).
It seems to be polyfilled by this third-party library: https://github.com/eligrey/FileSaver.js
The error you are seeing is caused by a reference to an undefined variable FileSaver - I guess that you are using FileSaver.js, and need to fix the import. You should also bear in mind that FileSaver is deprecated in favour of the download attribute. See this answer for details on how to use it.
Either way, in the interests of keeping your store light, you should save a reference to the PDF in your Redux store, rather than the string itself.
Related
Background
I built an app, which converts files from type A to type B (a binary file). I want to import and use a dummy file of type B to fill the data of file type A. The dummy always stays the same. The app has no backend. I want to share the html, so anything which requires turning off browser security etc., isn't an option.
Problem
At the moment, I load the files as I found here, but this works only with a backend server:
Requesting blob images and transforming to base64 with fetch API
import dummy from '../templates/Grid2.shp';
let hex = await fetch(dummy)
.then( response => response.blob() )
.then( blob => new Promise( callback =>{
let reader = new FileReader() ;
reader.onload = function(){
const serumShp = atob(this.result.substring(37)); // 37 strips the base64 info data:...
callback(binaryToHex(serumShp))
} ;
reader.readAsDataURL(blob) ;
}) ) ;
It works in my development but not at the built stage. As the browsers requests from the filesystem.
I found a solution over a file loader, but this solution also throws an error:
Using file-loader to load binary file in react
import/no-webpack-loader-syntax
Also, I don't see any configuration files for Webpack. As far as I have seen I would need to eject them, which is also not recommended.
Question:
How can I import binary files into my app without a backend server/any changes, etc.?
Sorry, I cannot help, but pointing out that there is a general discussion in CRA to support a more elegant way of importing binary/raw data. Sadly there doesn't seem to be much progress, the proposal is from 2018.
I am trying to save a variable's data into a text file and update the file every time the variable changes. I found solutions in Node.js and vanilla JavaScript but I cannot find a particular solution in React.js.
Actually I am trying to store Facebook Long Live Access Token in to a text file and would like to use it in the future and when I try importing 'fs' and implementing createFile and appendFile methods I get an error saying Method doesn't exist.
Please help me out. Here is the code below
window.FB.getLoginStatus((resp) => {
if (resp.status === 'connected') {
const accessToken = resp.authResponse.accessToken;
try {
axios.get(`https://graph.facebook.com/oauth/access_token?client_id=CLIENT_id&client_secret=CLIENT_SECRET&grant_type=fb_exchange_token&fb_exchange_token=${accessToken}`)
.then((response) => {
console.log("Long Live Access Token " + response.data.access_token + " expires in " + response.data.expires_in);
let longLiveAccessToken = response.data.access_token;
let expiresIn = response.data.expires_in;
})
.catch((error) => {
console.log(error);
});
}
catch (e) {
console.log(e.description);
}
}
});
React is a frontend library. It's supposed to be executed in the browser, which for security reasons does not have access to the file system. You can make React render in the server, but the example code you're showing is clearly frontend code, it uses the window object. It doesn't even include anything React-related at first sight: it mainly consists of an Ajax call to Facebook made via Axios library.
So your remaining options are basically these:
Create a text file and let the user download it.
Save the file content in local storage for later access from the same browser.
Save the contents in online storage (which could also be localhost).
Can you precise if any of these methods would fit your needs, so I can explain it further with sample code if needed?
I am using react to create front-end.
I have a download button which will trigger an action.
The action will use axios.post to call the server which will return a file.
The axios.response is something like this
resopnse.data: 'binary data of image file'
response.headers: {
cache-control:"public, max-age=0"
content-disposition:"attachment; filename="test.jpg""
content-type:"image/jpeg"
last-modified:"Mon, 22 Jan 2018 18:49:27 GMT"
}
response.data is tested using postman which converts the response to the correct image.
Now I am going to use eligrey's filesaver to save it.
This is what I have.
let fileName = getFileNameFromContentDisposition(response.headers);
let blob = new Blob([response.data], {type: response.headers["content-type"]});
fileSaver.saveAs(blob, fileName, true);
The code is tested using Chrome. The code will create a jpeg file, but it cannot be opened.
I played around with solutions provided for similar questions in GitHub and this website. But none of it is working.
I believe I am missing trivial setting to make this work.
The problem is not the library.
axios is the cause. The response from axios is already converted to json. So the binary data lost some information.
Even when the blob string fromaxios's reply is converted back to blob. It is a corrupted blob.
The workaround is to use fetch, and convert the response to response.blob().
I want to download file that can be in any format viz. pdf, jpeg, png, xlsx, csv etc. The download API on backend using pyramid framework is sending FileResponse as below:
def delivery_item_download_view(request, *args, **kw):
context = request.context
item_row = context.item_row
if item_row and item_row["deleted_at"] is None:
print(request.upload_dir+'/'+item_row["file_name"]+'.'+item_row["file_extension"])
response = FileResponse(
request.upload_dir+'/'+item_row["file_name"]+'.'+item_row["file_extension"],
request=request,
)
response.headers["attachment"] = item_row["name"];
return response
This, when executed using POSTMAN works as expected giving file as output. However,when tried implementing same using ReactJS, it's not working as expected. My client-code is as below:
onDownloadItem= (item) => {
console.log("item id is:", item.item_id)
var apiBaseUrl = "https://dev.incodax.com/api/deliveries_items/"+ item.item_id+ "/download";
fetch(apiBaseUrl, {
method: "GET",
}).then((res) => {
fileDownload(res,item.file_name)
console.log(res)
})
}
This fileDownload function simply downloading file but with no content inside. In downloaded file I could see something like:
[object Response]
I am getting 200 response from server. So I dont't think there is any issue with server side code. How can I handle it on client?
Thanks in advance
Will it suit you if you just redirected user to link to file? Browser will automatically handle it and download it.
The issue is in your fileDownload function which you do not post here. It's not clear what the first parameter is supposed to be but likely it is not the response object. Likely you at least need to pull the body out of the response and save that! The response body can be converted to a buffer object which could work (again it depends on what fileDownload is expecting):
res.arrayBuffer().then(buffer => {
fileDownload(buffer, item.file_name);
});
I'm on single page app using typescript and angular.
I'm using ng.Resource to fetch data from webapi
productResource.get({ userName: login.userName, password: login.password }, (data: Models.ICompany) => {
this.localStorageService.set<Models.ICompany>("CompanyData", data);
});
I've added angular-local-storage.d.ts file and also installed angularlocalstorage
but when I try to store the promise returned from webapi I'm getting an error "unable to get propery 'set' of undefined or null reference". Also I could not find 'set' / 'get' methods in angular-local-storage.js file. I'm guessing the error is producing because the 'set'/'get' methods are unknow in .js file.
Could you please help me to resolve this issue.
Or is there any best way to store the data in browser using angular.
I was having some trouble using localstorage in typescript too. What I did was:
I found a js file on github with some functions to access localstore. I wrote the same js file in Typescript and used that file. This has a cookie fallback.
here is the link to my version :
https://gist.github.com/davidcarm/eedb29feb25a7130d0f9ac01a7d11d3f (scroll to bottom)
once you imported the SimpleStore.ts file you just use these functions:
constructor(private simpleStore: SimpleStore){}
// to save a value
simpleStore.store('value_name',value);
// to access a value
simpleStore.store('value_name',undefined);
// to delete a value
simpleStore.store('value_name',null);
Cheers!