Start downloading file using JQuery - javascript

I want to start file downloading when I clicked the button.
I just have the path of the file.
How can I start downloading?
This is what I tried so far:
$('#download_button').click(function(){
var filepath = $(this).attr('data-filepath');
var do = 'file';
$(body).append(do);
});
What I am doing wrong.
I never want to redirect the page.
Is downloading start in browser or in software for downloading files if installed on client machine

Alternatively you can also set the top.location
$('#download_button').click(function(){
var filepath = $(this).attr('data-filepath');
top.location.href = filepath;
});

You cannot force a file to be downloaded in JavaScript.
What you can do is location.href = "somefile.ext";, however it will only be downloaded if the server includes Content-Disposition: attachment as one of its response headers to that file request.

If you want to download a file to the client, then do this:
$('#download_button').click(function(){
var filepath = $(this).attr('data-filepath');
location.href = filepath;
});
location.href will look for a page, but it will not find anything, so it will download the file instead.

You can create a form using jQuery and use the submit function. This will not change the URL in the address bar.
$('#download_button').click(function(){
var filepath = $(this).attr('data-filepath');
var form = $('<form>').attr('action', filepath);
form.submit();
});

Related

javascript - make browser send PDF file to download folder

How do I send a PDF file I am downloading from a server to the browser's download area instead of opening it in a browser window?
I am working with C# in Blazor. This is my current code, which I need to modify, but don't know how to (ofc I googled before asking here):
async void DownloadDocument(string apiURL, Guid ID)
{
JSRuntime.InvokeAsync<string>("open", $"{apiURL}/GetPDF/{ID}", "_blank");
}
The server returns a FileStreamResult here and the browser shows the file in a new tab. I want it to send it to its downloads folder instead.
You are invoking a JS Function called "open" with two params. (https://developer.mozilla.org/en-US/docs/Web/API/Window/open)
Try creating your own JS download function inside of a script file / tag and invoking it.
The crucial part to save a file in the downloads folder is to set the download attribute of the a tag.
It could look something like this.
inside wwwroot/index.html:
<script>
window.downloadFile = (fileName, pdfData) => {
const linkSource = `data:application/pdf;base64,${pdfData}`;
const downloadLink = document.createElement("a");
downloadLink.href = linkSource;
downloadLink.download = fileName;
downloadLink.click();
downloadLink.remove();
}
</script>
and in your blazor component:
async void DownloadDocument(string apiURL, Guid ID)
{
// call your api to download the file you want to download
var response = await Http.GetAsync($"{apiURL}/GetPDF/{ID}"));
// convert to base64
var pdfExportBytes = await response.Content.ReadAsByteArrayAsync();
var pdfExportB64 = Convert.ToBase64String(pdfExportBytes);
// invoke js download
await JSRuntime.InvokeVoidAsync("downloadFile", "FileName", pdfExportB64);
}
The file will still be opened if configured so in the users browser, but it will also be stored in the download folder.

How to rename pdf which saved on Server while opening in new tab

I'm writing a web application that, among other things, allows users to upload files to my server. In order to prevent name clashes and to organize the files, I rename them once they are put on my server.
My question is, is there any way to specify the name of a file to be downloaded.? So a user uploads a file named 'abc.pdf' and I rename it to '10.pdf', but when they download it I want the browser to save the file as 'abc.pdf' by default. is there any way to do it?
I referred this question
How to set name of file downloaded from browser?
But in my case, I am opening pdf by in new tab from javascript. when clicking on pdf will get the id which is equal to the name stored in the server, with that id will refer DB and fetch actual name using ajax. But How will I rename the filename from id to actual name?
$(document).on('click', '.file', function (e) {
var id = this.id+'.pdf';
$.ajax({
url: "<?php echo base_url() ?>/Directorylist/files",
type: "POST",
datatype: 'json',
success: function (data) {
var actual_name = data;
var win = window.open();
win.location.href="http://localhost:8080/panExplorer/uploads/"+id+"";
},
});
});
You can try to create a tag append it to body (it work without this in chrome but it require to be in document in Firefox) and click on it, (you need to call native click not jQuery method).
function download(url, fname) {
var a = $('<a/>').attr({
href: url,
download: fname,
target: '_blank'
}).appendTo('body');
a[0].click(); // native DOM function
a.remove();
}
and instead of
var win = window.open();
win.location.href="http://localhost:8080/panExplorer/uploads/"+id+"";
use:
download("http://localhost:8080/panExplorer/uploads/" + id, "some_other.pdf");
EDIT:
The other solution would be to create php file that will be proxy in downloading the files and you use same code but forward to the php file:
var win = window.open();
win.location.href="http://localhost:8080/panExplorer/download.php?file="+id;
and in download.php file you use:
// and you should check if there are no ".." in the filename,
// so no one will download your source code with `file=../index.php`
readfile("./upload/" . $_GET['file']);
and use solution from to download files How to set name of file downloaded from browser?
EDIT:
if you need to open the file but no download here is solution:
You need url that will have proper name so it need to end with /filename.pdf, the simplest way is to use url that look something like this:
/UploadFiles/id/your_filename.pdf
and you need to write script (or route in in your framework) that will open id and ignore the filename, the filename will be used by browser.

Open file from Firebase Storage in new table and not download

I have various buckets in Firebase Storage that all contain an html file. What I want to do is through Javascript, get the URL of a particular HTML file in a bucket, and then open it in a new tab. When I use the 'getDownloadURL' method, and pass the url to window.open what I'm finding is that a new tab opens temporarily, the file gets downloaded, and then the tab closes. Ideally, I would like to completely avoid downloading the file, and just view it. I believe this is happening because of the format of the URL itself:
https://firebasestorage.googleapis.com/v0/b/[project].appspot.com/o/[bucket]%2Fcreate.html?alt=media&token=[token]
Can anybody please help me use window.load to only open the html file in a new tab? I would prefer to not download the file at all, and I need the tab to remain open. Thanks in advance for any help!
var storage = firebase.storage();
var storageRef = storage.ref();
var reportFileRef = storageRef.child(currentUid + '/create.html');
reportFileRef.getDownloadURL().then(function(url) {
window.open(url, '_blank')
});
Setting the metadata correctly solved the Content-Disposition issue. Here is the function I've defined, where contenttype is either "text/html" or "image/png"
def uploadToFirebaseStorage(filename, filepath, user, report, contenttype):
my_file = open(os.path.join(filepath, filename), "rb")
my_bytes = my_file.read()
my_url = "https://firebasestorage.googleapis.com/v0/b/[project].appspot.com/o/" + filename
my_headers = { "Content-Type": contenttype }
my_request = urllib.request.Request(my_url, data=my_bytes, headers=my_headers)
try:
loader = urllib.request.urlopen(my_request)
except urllib.error.URLError as e:
message = json.loads(e.read())
return message["error"]["message"]
else:
return loader.read()

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 save html that was modified on the browser (the DOM) with Javascript/jQuery

First of all let me clarify that what I'm trying to do is for locally use only, users will have direct access to the html page.
What I'm trying to do is basically append and save text to an HTML file.
This is what I have.
HTML (index.html)
<div id="receiver"></div>
<button id="insertButton">Insert</button>
JS
$(document).ready( function() {
$('#insertButton').click(function(){
$('#receiver').append('<h1>Hi,</h1>','<p>How are you?</p>');
})
});
What I don't know is how to save the file (index.html) after the appending. Any idea how to do that? Is this even possible with Javascript or jQuery?
You could change your handler to do this:
$(document).ready( function() {
$('#insertButton').click(function(){
$('#receiver').append('<h1>Hi,</h1>','<p>How are you?</p>');
// Save the page's HTML to a file that is automatically downloaded.
// We make a Blob that contains the data to download.
var file = new window.Blob([document.documentElement.innerHTML], { type: "text/html" });
var URL = window.webkitURL || window.URL;
// This is the URL that will download the data.
var downloadUrl = URL.createObjectURL(file);
var a = document.createElement("a");
// This sets the file name.
a.download = "source.htm";
a.href = downloadUrl;
// Actually perform the download.
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
})
});
You should take a look at the compatibility matrix and documentation of URL over at MDN. Notably URL is not available for IE 9 or earlier. Same for Blob.
If I understand it correctly, you need it on local machine and for temporary usage then you can store it in cookies.
So whenever you load the page, check if cookie available, if yes then load data from cookies or load the fresh data.
You can use this data, unless and until cookies are not cleared.
Hope this helps...
Don't need any javascript. After the html is appended, just press Ctrl+S to save the file locally with modified html.

Categories

Resources