I am trying to use window.location.href in a loop to download multiple files
I have a table in which i can select file's, then i run a loop of selected and
try navigate to the file path to download the files.
I keep only getting the last file to download.
I think it's due to the location herf only taking action after my javascript finishes and not as the code runs.
When i have a break point on the window.location.herf it still only downloads the last file and only when i let the code run through.
Is there a better way to initiate multiple downloads from a javascript loop.
$("#btnDownload").click(function () {
var table = $('#DocuTable').DataTable();
var rows_selected = table.rows('.selected').data();
$.each(rows_selected, function (i, v) {
window.location.href = v.FilePath;
});
});
In some browsers (at least Google Chrome) support the follow:
$("<a download/>").attr("href", "https://code.jquery.com/jquery-3.1.0.min.js").get(0).click();
$("<a download/>").attr("href", "https://code.jquery.com/jquery-3.1.0.min.js").get(0).click();
$("<a download/>").attr("href", "https://code.jquery.com/jquery-3.1.0.min.js").get(0).click();
JSFiddle: https://jsfiddle.net/padk08zc/
I would make use of iframes and a script to force the download of the files as Joe Enos and cmizzi have suggested.
The answer here will help with JavaScript for opening multiple iframes for each file:
Download multiple files with a single action
The answers for popular languages will help with forcing downloads if the URL is actually something that can be served correctly over the web:
PHP: How to force file download with PHP
.Net: Force download of a file on web server - ASP .NET C#
NodeJS: Download a file from NodeJS Server using Express
Ruby: Force browser to download file instead of opening it
Ensure you change the links to point to your download script and also make sure you add the appropriate security checks. You wouldn't want to allow anyone to abuse your script.
Though this looks like an old post and I stumbled on this while trying to solve a similar issue. So, just giving a solution which might help. I was able to download the files but not in the same tab. You can just replace the event handler with download which is provided below. The urls is an array of presigned S3 URLs.
The entire code looks like below:
download(urls: any) {
var self = this;
var url = urls.pop();
setTimeout(function(){
var a = document.createElement('a');
a.setAttribute('href', url);
document.body.appendChild(a);
a.setAttribute('download', '');
a.setAttribute('target', '_blank');
a.click();
// a.remove();
}, 1000)
}
Related
I have an html file that I would like to make available for offline use. This can be achieved easily by simply right clicking on the link on a desktop browser, then choosing "save as".
However, on a mobile device, I have tried using the download attribute on the anchor tag like so:
<a href="index.html" download>Download the page here.</a>
This seems to just take me to the page instead of downloading it.
My main goal is just to allow the user to download an html file to their mobile device.
There really isn't a right-click on mobile and holding down on the link shows a menu, but download isn't among them. The mobile browser itself may have a mechanism for saving a page once opened, but this would be sort of hard to walk the user through, and of course I'll have no idea what the mobile browser the user is using.
A special note here, the webpage I am trying to download does not have assets like images or style script files that need loaded in, all the assets are self-contained in the html file itself.
I actually came up with a solution to the problem, so I'll share it here, but I'm finding it hard to believe that there is not an easier way to do this.
My solution was essentially this, make an asynchronous request for the html file and read its text as a string. Then use that string to make a text blob and download it. Furthermore, to make sure the asset could be obtained from a local machine I served the data with a php file containing a header to ignore the cross origin restriction. (I didn't use fetch because I wanted to use settimeout).
To request an index.html file from the location https://www.mypage.com/:
Here is the downloader.php file located in the base directory:
header('Access-Control-Allow-Origin: *');
?>
<?php include_once 'index.html';?>
The html file the user clicks:
<!DOCTYPE html>
<html>
<body>
<button onclick="downloadPageAsText('https://www.mypage.com/downloader.php', 'index', '.html');">Download</button>
</body>
</html>
The functions to allow downloading:
function downloadPageAsText(url, basename, suffix){
let xhttp = new XMLHttpRequest();
xhttp.timeout = 1000;
xhttp.ontimeout = function(e) {
alert("Request timed out. Try again later");
};
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
saveStringToTextFile(xhttp.responseText, basename, suffix);
}
};
xhttp.open("GET", url, true);
xhttp.send();
}
function saveStringToTextFile(str1, basename = "myfile", fileType = ".txt") {
let filename = basename + fileType;
let blobVersionOfText = new Blob([str1], {
type: "text/plain"
});
let urlToBlob = window.URL.createObjectURL(blobVersionOfText);
let downloadLink = document.createElement("a");
downloadLink.style.display = "none";
downloadLink.download = filename;
downloadLink.href = urlToBlob;
document.body.appendChild(downloadLink);
downloadLink.click();
downloadLink.parentElement.removeChild(downloadLink);
}
Is there an easier way to allow the user to download an html file to their mobile device?
After help in the comments I found that adding the Content-Disposition header in the PHP file prompts the mobile browsers to use their download mechanisms.
It looks like there are 2 relatively simple ways to cause the html file to download.
You can use the anchor tag's download attribute which is supposed to prompt the browser to download the file instead of displaying it. Here is an example of its use:
Click to download
However, this only works for same-origin URLs, so although it may fit your use-case but not mine as I need the file to download from cross-origin URLS.
A second simpler way of making the html file download rather than display (using PHP), is to use the Content-Dispostion header which tells the users browser it should be downloading the file.
Here is an example of a PHP file called download.php, which will cause desiredpage.html to download with a suggested name of suggestname.html, using just an anchor tag from the client side.
<?php
$contents=file_get_contents("desiredpage.html");
$filename="suggestedname.html";
header('Access-Control-Allow-Origin: *');
header("Content-disposition:attachment;filename=".$filename);
echo $contents;
?>
And here is the anchor tag on the client-side:
Click here to download
Reference:
Download Link not working in html
With useful comments from:
Anirban and Christopher.
I've converted an existing web application (HTML5, JS, CSS, etc.) into a Windows UWP app so that (hopefully) I can distribute it via the Windows Store to Surface Hubs so it can run offline. Everything is working fine, except PDF viewing. If I open a PDF in a new window, the Edge-based browser window simply crashes. If I open an IFRAME and load PDFJS into it, that also crashes. What I'd really like to do is just hand off the PDF to the operating system so the user can view it in whatever PDF viewer they have installed.
I've found some windows-specific Javascript APIs that seem promising, but I cannot get them to work. For example:
Windows.System.Launcher.launchUriAsync(
new Windows.Foundation.Uri(
"file:///"+
Windows.ApplicationModel.Package.current.installedLocation.path
.replace(/\//g,"/")+"/app/"+url)).then(function(success) {
if (!success) {
That generates a file:// URL that I can copy into Edge and it shows the PDF, so I know the URL stuff is right. However, in the application it does nothing.
If I pass an https:// URL into that launchUriAsync function, that works. So it appears that function just doesn't like file:// URLs.
I also tried this:
Windows.ApplicationModel.Package.current.installedLocation.getFileAsync(url).then(
function(file) { Windows.System.Launcher.launchFileAsync(file) })
That didn't work either. Again, no error. It just didn't do anything.
Any ideas of other things I could try?
-- Update --
See the accepted answer. Here is the code I ended up using. (Note that all my files are in a subfolder called "app"):
if (location.href.match(/^ms-appx:/)) {
url = url.replace(/\?.+/, "");
Windows.ApplicationModel.Package.current.installedLocation.getFileAsync(("app/" + url).replace(/\//g,"\\")).then(
function (file) {
var fn = performance.now()+url.replace(/^.+\./, ".");
file.copyAsync(Windows.Storage.ApplicationData.current.temporaryFolder,
fn).then(
function (file2) {
Windows.System.Launcher.launchFileAsync(file2)
})
});
return;
}
Turns out you have to turn the / into \ or it won't find the file. And copyAsync refuses to overwrite, so I just use performance.now to ensure I always use a new file name. (In my application, the source file names of the PDFs are auto-generated anyway.) If you wanted to keep the filename, you'd have to add a bunch of code to check whether it's already there, etc.
LaunchFileAsync is the right API to use here. You can't launch a file directly from the install directory because it is protected. You need to copy it first to a location that is accessible for the other app (e.g. your PDF viewer). Use StorageFile.CopyAsync to make a copy in the desired location.
Official SDK sample: https://github.com/Microsoft/Windows-universal-samples/tree/master/Samples/AssociationLaunching
I just thought I'd add a variation on this answer, which combines some details from above with this info about saving a blob as a file in a JavaScript app. My case is that I have a BLOB that represents the data for an epub file, and because of the UWP content security policy, it's not possible simply to force a click on a URL created from the BLOB (that "simple" method is explicitly blocked in UWP, even though it works in Edge). Here is the code that worked for me:
// Copy BLOB to downloads folder and launch from there in Edge
// First create an empty file in the folder
Windows.Storage.DownloadsFolder.createFileAsync(filename,
Windows.Storage.CreationCollisionOption.generateUniqueName).then(
function (file) {
// Open the returned dummy file in order to copy the data to it
file.openAsync(Windows.Storage.FileAccessMode.readWrite).then(function (output) {
// Get the InputStream stream from the blob object
var input = blob.msDetachStream();
// Copy the stream from the blob to the File stream
Windows.Storage.Streams.RandomAccessStream.copyAsync(input, output).then(
function () {
output.flushAsync().done(function () {
input.close();
output.close();
Windows.System.Launcher.launchFileAsync(file);
});
});
});
});
Note that CreationCollisionOption.generateUniqueName handles the file renaming automatically, so I don't need to fiddle with performance.now() as in the answer above.
Just to add that one of the things that's so difficult about UWP app development, especially in JavaScript, is how hard it is to find coherent information. It took me hours and hours to put the above together from snippets and post replies, following false paths and incomplete MS documentation.
You will want to use the PDF APIs https://github.com/Microsoft/Windows-universal-samples/tree/master/Samples/PdfDocument/js
https://github.com/Microsoft/Windows-universal-samples/blob/master/Samples/PdfDocument/js/js/scenario1-render.js
Are you simply just trying to render a PDF file?
In my angularjs (angularjs 1.3) app there is a place where the user can download a pdf file.
This is done in a controller using:
$window.location.href = 'pdf/123456';
which saves the file on the users computer. The url in the broswer is never really changed, the user is still on the same page in the angular app.
When I set the locations this way however, ongoing requests get cancelled when using Firefox. Using Chrome there is no problem. The only solution I've come up with is to wait with other requests until the pdf is downloaded but since that can take some time I would like to start them before the download is complete.
Is there any way of fixing this? Can I download the file in any other way? I don't want to open a popup window.
Another way to download a file is to create an <a> tag with the file as target and simulate a click on it. Like this:
var a = document.createElement('a');
a.href = 'pdf/123456';
a.download = 'document_name';
a.target = '_blank';
a.click();
I am attempting to write a script in javascript to scrape images from a site and save them to my computer.
I have managed to make the script isolate the image tag that contains the image I want using jQuery. So I have a jquery selection:
<img src="sourceofimage.com/path/img">
My question is how can I now save this image to my computer?
I tried searching but all the results I got were about doing things like making a download button or other user facing tasks. To be clear, I will be the only one running this script and it will be run by pasting it into the console.
I only want a way to programmatically download the image and set its filename once jQuery has isolated it. Is this possible?
Edit: Can somebody kindly explain why this is receiving so many downvotes?
This would apply to every single image on your page which is the direct child of an anchor, but you could use:
'$('a > img').each(function(){
var $this = $(this);
$this.parent('a').attr('href', $this.attr('src'));
});
But it would do the job.
Only thing is though, users with JS disabled will see an anchor with an empty href. The following would achieve the same end result with the added benefit of simplifying your code (cleaner HTML) and adding graceful degradation:
'<img src="folio/1.jpg" class="downloadable" />
$('img.downloadable').each(function(){
var $this = $(this);
$this.wrap('<a href="' + $this.attr('src') + '" download />')
Try the fs library
fs.writeFile('logo.png', imagedata, 'binary', function(err){
if (err) throw err
console.log('File saved.')
Within a web browser it basically can't be done you can't write directly to the file system (may be possible with browser extensions however I haven't looked at this in a while).
Using node there's nothing stopping you doing something like:
Use http to retrieve the HTML
Use jQuery to parse the html - something like $(html).find('img');
Generate a http request to each image to download them
Save it to disk using fs
Let's say I have download links for files on my site.
When clicked these links send an AJAX request to the server which returns the URL with the location of the file.
What I want to do is direct the browser to download the file when the response gets back. Is there a portable way to do this?
We do it that way:
First add this script.
<script type="text/javascript">
function populateIframe(id,path)
{
var ifrm = document.getElementById(id);
ifrm.src = "download.php?path="+path;
}
</script>
Place this where you want the download button(here we use just a link):
<iframe id="frame1" style="display:none"></iframe>
download
The file 'download.php' (needs to be put on your server) simply contains:
<?php
header("Content-Type: application/octet-stream");
header("Content-Disposition: attachment; filename=".$_GET['path']);
readfile($_GET['path']);
?>
So when you click the link, the hidden iframe then gets/opens the sourcefile 'download.php'. With the path as get parameter.
We think this is the best solution!
It should be noted that the PHP part of this solution is a simple demonstration and potentially very, very insecure. It allows the user to download any file, not just a pre-defined set. That means they could download parts of the source code of the site itself, possibly containing API credentials etc.
I have created an open source jQuery File Download plugin (Demo with examples) (GitHub) which could also help with your situation. It works pretty similarly with an iframe but has some cool features that I have found quite handy:
User never leaves the same page they initiated a file download from. This feature is becoming crucial for modern web applications
Tested cross browser support (including mobile!)
It supports POST and GET requests in a manner similar to jQuery's AJAX API
successCallback and failCallback functions allow for you to be explicit about what the user sees in either situation
In conjunction with jQuery UI a developer can easily show a modal telling the user that a file download is occurring, disband the modal after the download starts or even inform the user in a friendly manner that an error has occurred. See the Demo for an example of this.
Just call window.location.href = new_url from your javascript and it will redirect the browser to that URL as it the user had typed that into the address bar
Reading the answers - including the accepted one I'd like to point out the security implications of passing a path directly to readfile via GET.
It may seem obvious to some but some may simply copy/paste this code:
<?php
header("Content-Type: application/octet-stream");
header("Content-Disposition: attachment; filename=".$_GET['path']);
readfile($_GET['path']);
?>
So what happens if I pass something like '/path/to/fileWithSecrets' to this script?
The given script will happily send any file the webserver-user has access to.
Please refer to this discussion for information how to prevent this: How do I make sure a file path is within a given subdirectory?
If this is your own server application then i suggest using the following header
Content-disposition: attachment; filename=fname.ext
This will force any browser to download the file and not render it in the browser window.
Try this lib https://github.com/PixelsCommander/Download-File-JS it`s more modern than all solutions described before because uses "download" attribute and combination of methods to bring best possible experience.
Explained here - http://pixelscommander.com/en/javascript/javascript-file-downliading-ignore-content-type/
Seems to be ideal piece of code for starting downloading in JavaScript.
A agree with the methods mentioned by maxnk, however you may want to reconsider trying to automatically force the browser to download the URL. It may work fine for binary files but for other types of files (text, PDF, images, video), the browser may want to render it in the window (or IFRAME) rather than saving to disk.
If you really do need to make an Ajax call to get the final download links, what about using DHTML to dynamically write out the download link (from the ajax response) into the page? That way the user could either click on it to download (if binary) or view in their browser - or select "Save As" on the link to save to disk. It's an extra click, but the user has more control.
To get around the security flaw in the top-voted answer, you can set the iframe src directly to the file you want (instead of an intermediate php file) and set the header information in an .htaccess file:
<Files *.apk>
ForceType application/force-download
Header set Content-Disposition attachment
Header set Content-Type application/vnd.android.package-archive
Header set Content-Transfer-Encoding binary
</Files>
I suggest to make an invisible iframe on the page and set it's src to url that you've received from the server - download will start without page reloading.
Or you can just set the current document.location.href to received url address. But that's can cause for user to see an error if the requested document actually does not exists.
In relation to the top answer I have a possible solution to the security risk.
<?php
if(isset($_GET['path'])){
if(in_array($_GET['path'], glob("*/*.*"))){
header("Content-Type: application/octet-stream");
header("Content-Disposition: attachment; filename=".$_GET['path']);
readfile($_GET['path']);
}
}
?>
Using the glob() function (I tested the download file in a path one folder up from the file to be downloaded) I was able to make a quick array of files that are "allowed" to be downloaded and checked the passed path against it. Not only does this insure that the file being grabbed isn't something sensitive but also checks on the files existence at the same time.
~Note: Javascript / HTML~
HTML:
<iframe id="download" style="display:none"></iframe>
and
<input type="submit" value="Download" onclick="ChangeSource('document_path');return false;">
JavaScript:
<script type="text/javascript">
<!--
function ChangeSource(path){
document.getElementByID('download').src = 'path_to_php?path=' + document_path;
}
-->
</script>
I'd suggest window.open() to open a popup window. If it's a download, there will be no window and you will get your file. If there is a 404 or something, the user will see it in a new window (hence, their work will not be bothered, but they will still get an error message).
Why are you making server side stuff when all you need is to redirect browser to different window.location.href?
Here is code that parses ?file= QueryString (taken from this question) and redirects user to that address in 1 second (works for me even on Android browsers):
<script type="text/javascript">
var urlParams;
(window.onpopstate = function () {
var match,
pl = /\+/g, // Regex for replacing addition symbol with a space
search = /([^&=]+)=?([^&]*)/g,
decode = function (s) { return decodeURIComponent(s.replace(pl, " ")); },
query = window.location.search.substring(1);
urlParams = {};
while (match = search.exec(query))
urlParams[decode(match[1])] = decode(match[2]);
})();
(window.onload = function() {
var path = urlParams["file"];
setTimeout(function() { document.location.href = path; }, 1000);
});
</script>
If you have jQuery in your project definitely remove those window.onpopstate & window.onload handlers and do everything in $(document).ready(function () { } );