Download PDF from url react - javascript

I have a publicly accessible url to a PDF in Google Cloud Storage. I want to be able to create a button/link in react which allows users to download this PDF to their own computer. I'm wondering what is the best approach to do this and which libraries would be of help? Is there any documentation on this? Thanks

In order to force download a file, you have a number of options. First, the easiest is using the download attribute of an anchor tag:
PDF
However, this is not supported on IE and a number of other browsers in their earlier versions. But the maximum impact of this is it will open in a new tab which in my opinion is graceful degradation. See the full list of supported versions.
If this is not enough, you have to make some changes server-side. You can configure a server in many ways, but as an example, a .htaccess file can have the following:
<Files *.pdf>
Header set Content-Disposition attachment
</Files>

You can dynamically generate a link or button. Snippet bellow:
var sampleBytes = new Int8Array(4096); // In your case it should be your file
var saveByteArray = (function () {
var a = document.createElement("a");
document.body.appendChild(a);
a.style = "display: none";
return function (data, name) {
var blob = new Blob(data, {type: "octet/stream"}), // or application/pdf
url = window.URL.createObjectURL(blob);
a.href = url;
a.download = name;
a.click();
window.URL.revokeObjectURL(url);
};
}());
saveByteArray([sampleBytes], 'example.txt'); // You can define the filename

Related

Download pdf without opening in browser

I want to download pdf file directly without viewing, i have tries following things till now but nothing is helping.
1- window.open("https://s3-link1.pdf", 'Download');
2- <a href="https://s3-link1.pdf" download>Link</a>
Link - https://s3-link1.pdf
Assume my domain is https://www.somedomain.com
I somewhere read we can't download cross-origin files. content-disposition header is required to be passed from backend. I am puzzled here. Another csv file of cross-origin is being downloaded easily.
https://s3-link2.csv
I just need to download pdf file using javascript. Please guide me.
Try with fetch.
fetch("https://s3-link1.pdf", {
method: 'GET'
}).then(resp => resp.blob())
.then(blob => {
const url = window.URL.createObjectURL(blob);
const a = document.createElement('a');
a.style.display = 'none';
a.href = url;
a.download = "name"; // the filename you want
document.body.appendChild(a);
a.click();
window.URL.revokeObjectURL(url);
})
Option 1:
with jQuery you can try this:
$.get("https://s3-link1.pdf", function (result)
{
var blob = new Blob([result]);
var link = document.createElement('a');
link.href = window.URL.createObjectURL(blob);
link.download = "myFileName.pdf";
link.click();
});
Option 2:
The download attribute works in all modern browsers, including MS Edge, but not Internet Explorer.
In the latest versions of Chrome, you cannot download cross-origin files (they have to be hosted on the same domain).
<a href="https://s3-link1.pdf" download>Download PDF</a>
Find more about it here on this blog: https://actualwizard.com/html-force-download-file

How can I download a pdf from a url using javascript?

I need to download pdf's from one of our online resources.There is no built in function to batch download.The only way to do it is to navigate to each pdf file, click to open, then click download.
There are several thousand files and this would take a very long time to do.
I got around this in the past using javascript. I gathered all the links to the pdfs, put them in a csv, and had the code loop through each link, download, and move onto the next link.
Unfortunately, I have lost that code and my efforts to recreate it have been unsuccessful.
I have tried everything in this article: How to download PDF automatically using js?
I have tried the code from this article (which I'm pretty sure is what I did before): https://www.convertplug.com/plus/docs/download-pdf-file-forcefully-instead-opening-browser-using-js/
This is what I think should work...per the second article I referenced above
function download_file(fileURL, fileName) {
var link = document.createElement('a');
link.href = fileURL;
link.download = 'file.pdf';
link.dispatchEvent(new MouseEvent('click'));
}
var fileURL = "link/to/pdf";
var fileName = "test.pdf";
download(fileURL,fileName);
The code above is just to test download one file from a hardcoded URL. If it worked as intended, when the page is loaded, it should download the pdf from the provided url. Instead, it doesn't do anything on load or refresh.
Any suggestions?
Please check
https://stackoverflow.com/a/18983688/6923146
click me
Another one
https://stackoverflow.com/a/45905238/6923146
function download(url, filename) {
fetch(url).then(function(t) {
return t.blob().then((b)=>{
var a = document.createElement("a");
a.href = URL.createObjectURL(b);
a.setAttribute("download", filename);
a.click();
}
);
});
}
download("https://get.geojs.io/v1/ip/geo.json","geoip.json")
download("data:text/html,Hello Developer!", "HelloDeveloper.txt");
I hope it helpfull
https://www.convertplug.com/plus/docs/download-pdf-file-forcefully-instead-opening-browser-using-js/
You must add link element to DOM
function download_file(fileURL, fileName) {
var link = document.createElement('a');
link.href = fileURL;
link.download = fileName;
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
}
var fileURL = "https://cdn.sstatic.net/clc/img/jobs/bg-remote-header-sm.png";
var fileName = "test.pdf";
download_file(fileURL, fileName); // fix function name
Link must be in same origin
The download attribute on anchor was ignored because its href URL has a different security origin.

Javascript - auto download a resource

I have a list of URLS of media (photos + videos) i want to download.
Of course, i can dump the file into wget but i was thinking if it was posible to do it client-side.
My node.js server can inject the client with the resources in the form an link.
Then i found this website on how to download the link
https://ourcodeworld.com/articles/read/189/how-to-create-a-file-and-generate-a-download-with-javascript-in-the-browser-without-a-server
The problem is that the user will have to click each resource to download it, which is extremely time consuming. I would rather use wget than that.
I believe that for security concerns auto downloading is not supported.
But is there a way to automatically download all the resources without user interface?
Kinda like, the server keeps serving the URL resources, the client auto downloads them, until no more resources are left to serve.
EDIT: Or maybe, with one click of a button, instead of downloading one resource, loop and download through all of them
you can make an onclick event for a link;
<a onclick="specialOnClick">download ALL</a>
<script>
function specialOnClick() {
window.open('mysite.com/file1');
window.open('mysite.com/file2');
window.open('mysite.com/file3');
}
</script>
ES6 version
const autoDownloadFile = (href = ``, title = ``) => {
const a = document.createElement("a");
a.setAttribute("href", href);
a.setAttribute("download", title);
a.setAttribute("target", "_blank");
a.click();
};
// autoDownloadFile(`https://cdn.xgqfrms.xyz/logo/icon.png`, `icon`);
const autoDownloadFile = (href = ``, title = ``) => {
const a = document.createElement("a");
a.setAttribute("href", href);
a.setAttribute("download", title);
a.setAttribute("target", "_blank");
a.click();
};
autoDownloadFile(`https://cdn.xgqfrms.xyz/logo/icon.png`, `icon`);

send file from server to client on bokeh

I have made a user interface to fetch data from a MySQL table and visualize it. It is running on a bokeh server. My users connect remotely to the server using their browser (firefox). This works perfectly fine: I simply import the table into a pandas dataframe.
My users also need to download the table as excel. This means I cannot use the export_csv example which is pure javascript.
I have no experience with JavaScript. All I want is to transfer a file from the directory where my main.py is to the client side.
The technique I have tried so far is to join a normal on_click callback to a button, export the information I need to 'output.xls', then change a parameter from a dummy glyph which in turn runs a Javascript code. I got the idea from Bokeh widgets call CustomJS and Python callback for single event? . Note I haven't set the alpha to 0, so that I can see if the circle is really growing upon clicking the download button.
At the bottom of my message you can find my code. You can see I have tried with both XMLHttpRequest and with Fetch directly. In the former case, nothing happens. In the latter case I obtain a file named "mydata.xlsx" as expected, however it contains only this raw text: <html><title>404: Not Found</title><body>404: Not Found</body></html>.
Code:
p = figure(title='mydata')
#download button
download_b = Button(label="Download", button_type="success")
download_b.on_click(download)
#dummy idea from https://stackoverflow.com/questions/44212250/bokeh-widgets-call-customjs-and-python-callback-for-single-event
dummy = p.circle([1], [1],name='dummy')
JScode_xhr = """
var filename = p.title.text;
filename = filename.concat('.xlsx');
alert(filename);
var xhr = new XMLHttpRequest();
xhr.open('GET', '/output.xlsx', true);
xhr.responseType = 'blob';
xhr.onload = function(e) {
if (this.status == 200) {
var blob = this.response;
alert('seems to work...');
if (navigator.msSaveBlob) {
navigator.msSaveBlob(blob, filename);
}
else {
var link = document.createElement("a");
link = document.createElement('a');
link.href = URL.createObjectURL(blob);
window.open(link.href, '_blank');
link.download = filename;
link.target = "_blank";
link.style.visibility = 'hidden';
link.dispatchEvent(new MouseEvent('click'));
URL.revokeObjectURL(url);
}
}
else {
alert('Ain't working!');
}
};
"""
JScode_fetch = """
var filename = p.title.text;
filename = filename.concat('.xlsx');
alert(filename);
fetch('/output.xlsx').then(response => response.blob())
.then(blob => {
alert(filename);
//addresses IE
if (navigator.msSaveBlob) {
navigator.msSaveBlob(blob, filename);
}
else {
var link = document.createElement("a");
link = document.createElement('a')
link.href = URL.createObjectURL(blob);
window.open(link.href, '_blank');
link.download = filename
link.target = "_blank";
link.style.visibility = 'hidden';
link.dispatchEvent(new MouseEvent('click'))
URL.revokeObjectURL(url);
}
return response.text();
});
"""
dummy.glyph.js_on_change('size', CustomJS(args=dict(p=p),
code=JScode_fetch))
plot_tab = Panel(child=row(download_b,p),
title="Plot",
closable=True,
name=str(self.test))
def download():
writer = pd.ExcelWriter('output.xlsx')
data.to_excel(writer,'data')
infos.to_excel(writer,'info')
dummy = p.select(name='dummy')[0]
dummy.glyph.size = dummy.glyph.size +1
Trying out Eugene Pakhomov's answer, I found what was the issue.
The javascript code I named JScode_fetch is almost correct, however I get a 404 because it is not pointing correctly to the right path.
I made my application in the directory format: I changed my .py file to main.py, placed it into a folder called app, and changed this one line of code in JScode_fetch:
fetch('/app/static/output.xlsx', {cache: "no-store"}).then(response => response.blob())
[...]
You can see the problem was that it was trying to access localhost:5006/output.xlsx, instead of localhost:5006/app/output.xlsx. As it is in directory format, the right link is now localhost:5006/app/static/output.xlsx to count for the static directory.
I also changed a few lines in the download function:
def download():
dirpath = os.path.join(os.path.dirname(__file__),'static')
writer = pd.ExcelWriter(os.path.join(dirpath,'output.xlsx'))
writer = pd.ExcelWriter('output.xlsx')
data.to_excel(writer,'data')
infos.to_excel(writer,'info')
dummy = p.select(name='dummy')[0]
dummy.glyph.size = dummy.glyph.size +1
Now it is working flawlessly!
edit: I have added , {cache: "no-store"} within the fetch() function. Otherwise the browser thinks the file is the same if you have to download a different dataframe excel while using the same output.xlsx filename. More info here.
bokeh serve creates just a few predefined handlers to serve some static files and a WebSocket connection - by default, it doesn't have anything to serve files from the root of the project.
Instead of using the one-file format, you can try using the directory format, save your files to static directory and download them from /static/.
One downside of this approach is that you still have to write that convoluted code to just make your backend create the file before a user downloads it.
The best solution would be to go one step further and embed Bokeh Server as a library into your main application. Since you don't have any non-Bokeh code, the simplest way would be to go with Tornado (an example).
bokeh.server.server.Server accepts extra_patterns argument - you can add a handler there to dynamically create Excel files and serve them from, say, /data/. After all that, the only thing that you need in your front-end is a single link to the Excel file.

How to show save file dialog in Safari?

I need help. I have an angular app and by using DocRaptor want to generate PDF and save it as file. But I cant trigger the dialog to save file in Safari with any method what I have found on Stack Overflow. Those methods open file in current browser tab and replace site html or open file in new tab. No one cant shows the dialog. Here the examples what I have already tried to use. Environment MacOS - EL Capitan. Safari 9.0.3
Solution #1
var content = 'file content for example';
var blob = new Blob([ content ], { type : 'text/plain' });
$scope.url = (window.URL || window.webkitURL).createObjectURL( blob );
Example jsfiddle. Shows file in current tab. Replaces site. But works in Chrome.
Solution #2
<a target="_self" href="mysite.com/uploads/ahlem.pdf" download="foo.pdf">
Example jsfiddle. Doesnt work at all in Safari. Works in Chrome.
Solution #3
<a class="btn" ng-click="saveJSON()" ng-href="{{ url }}">Export to JSON</a>
and
$scope.saveJSON = function () {
$scope.toJSON = '';
$scope.toJSON = angular.toJson($scope.data);
var blob = new Blob([$scope.toJSON], { type:"application/json;charset=utf-8;" });
var downloadLink = angular.element('<a></a>');
downloadLink.attr('href',window.URL.createObjectURL(blob));
downloadLink.attr('download', 'fileName.json');
downloadLink[0].click();
};
Example Code Snippet. Shows the file content instead of document's html.
Solution #4
function download(text, name, type) {
var a = document.getElementById("a");
var file = new Blob([text], {type: type});
a.href = URL.createObjectURL(file);
a.download = name;
}
Example Code Snippet. Replace document with file content in Safari. Works in Chrome.
And similar Solution #5
function download(text, name, type) {
var a = document.createElement("a");
var file = new Blob([text], {type: type});
a.href = URL.createObjectURL(file);
a.download = name;
a.click();
}
Example jsfiddle. Doesnt work at all in Safari. Works in Chrome.
Also I have tried to use libraries like:
FileSaver - It opens file in Safari instead of document. So you should click Cmd+S. Example.
If we use type 'pplication/octet-stream' the name of file will be unknown or there was be an error 'Failed to load resource: Frame load interrupted'. Issue.
Second library Downloadify - doesnt work in Safari at all. Issue.
Angular library nw-fileDialog - instead of save as it shows choose file. Issue.
DocRaptor has own example with jQuery.
Example with angular in jsfiddle. It works in Chrome but in Safari example doesnt work be cause of error with SAMEORIGIN
Refused to display 'https://docraptor.com/docs' in a frame because it set 'X-Frame-Options' to 'SAMEORIGIN'.
But if we reproduce it on server and change url on 'https://docraptor.com/docs.pdf' it works and open file in new tab and automatically download the file so you cant choose a folder and after download user see white empty screen tab in browser. If we specify form target="_self" it will work perfect, but console will have an error 'Failed to load resource:'.
I will appreciate any help with this problem.
Thanks.
Regards.
Try using Blob file for this:
// Buffer can be response from XMLHttpRequest/Ajax or your custom Int32 data
function download(buffer, filename) {
var file = new Blob([buffer], {
type: 'application/octet-stream' // Replace your mimeType if known
});
var fileReader = new FileReader();
fileReader.onloadend = function(e) {
var converted = e.target.result;
converted.name = filename;
converted.webkitRelativePath = filename;
var iframe = document.createElement('iframe');
iframe.style.display = 'none';
document.body.appendChild(iframe);
iframe.src = converted;
};
fileReader.onerror = function(e) {
throw new Error('Something is wrong with buffer data');
};
fileReader.file = file;
fileReader.readAsDataURL(file);
}
It basically uses filebuffer and download that as an iframe content. Make sure to hook correct mime type so that safari security system will recieved analyse filetype.
Ideally, Solution #2 would be the answer, but the download attribute does not yet have cross-browser support.
So you have to use a <form> to create the download. As you noted, DocRaptor's jQuery example uses this technique.
The SAMEORIGIN error is actually because JSFiddle is running the code in an iFrame with their origin settings. If you run this straight from your Angular application, you shouldn't have any problems.

Categories

Resources