How can I print a PDF fetched via an ajax request? - javascript

I'm having a form that once submitted, the PHP generates a PDF file and sends it to the client. Everything works fine so far. What I'm having trouble with is that I need to trigger window.print() on the window containing the received pdf. Is there a way to make the printing wizard appear for the received pdf file?
Here is the code I have
//The #options is a form that once submitted is sends the requested PDF to the browser
$('#options').on('submit', function(e){
if($(this).find('[name="action"]').val() == 'print')
{
var url = $(this).attr('action') || document.URL;
e.preventDefault();
$.post(url, $(this).serializeArray(),function(pdf){
// Open the printing wizard for the requested document
});
}
else
{
// The PDF is displayed normally
return true;
}
});
I'm not even sure if what I want to do is possible. Is is possible for example to open the PDF in a new tab and call window.print() there?

One easy approach for this is to put the PDF file in a new iFrame.
Then you can print the complete content inside the iframe using window.print(); function.
<html>
<head>
<title>Print Test Page</title>
<script>
function printPDF() {
window.frames["print_frame"].window.focus();
window.frames["print_frame"].window.print();
}
</script>
</head>
<body>
Some content here
<iframe name=print_frame width=0 height=0 frameborder=0 src=about:blank>
Your PDF is loaded here
</iframe>
Some more content here
</body>
</html>
Now call window.print(); function when you want to print your pdf.

To open PDF in new window, you need to essentially generate an GET request (so that window can be open via URL) - one of the simple way is to code your server side code to accept the input parameters via query string. Better way is to use POST request (as you are currently doing) to generate the PDF at the server side and cache it in temp location, then return some token/ticket (e.g. it can be as simple as temp file name) to the browser. This token would be used in GET request to get the PDF file - GET request would go to server that would simply read the file off temp location and return it back as inline ((i.e. header content-disposition: inline;). Then you may try window.print() to print it. Similar ways can be used with iframe (with contentWindow.print()).
However, you may find that these solutions may not work - for example, there is no PDF plugin to display the PDF inline (or user has chosen always open file externally). Or it may not work across browser. So yet another (and IMO better) way is to embed java-script within PDF it self to instruct for print as soon as the file is opened.
For example, see this PHP code example that would embed java-script in PDF generation for auto printing - the example is using FPDF for PDF generation.

Related

Save PDF from window.print in Javascript

Good day,
I'm able to print a page using javascript. Using this codes:
var win = window.open('', 'print', 'height=720,width=300');
...
win.document.write(document.getElementById("myDivToPrint").innerHTML);
win.document.close();
win.focus();
win.print();
But my problem is, is there a way to save this on my server api?
I tried this,
var myPdf = win.output(); // Doesn't work, not found
I want to get at least the encoding of the pdf to be able to save it on my server. Is it possible? if yes, please help me how.
You can't use print if you want to save the PDF as print uses the browser print function.
if you use jQuery check this previous post Generate pdf from HTML in div using Javascript
You'll need to convert the HTML in PDF and then send a request to your server to save the file

Linking to a download in HTML

I have to create a online time-table for the school. The part what is troubling me at the moment is not to be able to download a file by clicking on the filename.
I try to download a file by clicking on a button or a link with html/php maybe javascript but for javascript I should somehow combine php and javascript because javascript has no readfile-function.
Some of my attempts:
Download
This just shows the content of the file in the web browser but I am not able to download it. The content of my testmove.txt is testmove123, so I just see the text testmove123 in my browser.
Another example:
Javascript:
function download(file)
{
window.location=file;
}
+html:
<input type="button" value="Download" onClick="download('dateiupload/testmove.txt')" >
Makes the same.
Another example:
Javascript:
function download(path)
{
var ifrm = document.getElementById("frame");
ifrm.src = path;
}
+html:
<iframe id="frame" style="display:none"></iframe>
download
By clicking on "Download" the javascript function starts but nothing else happens and I see the same site.
Another example (with php):
Javascript:
function download(path)
{
var ifrm = document.getElementById(frame);
ifrm.src = "download.php?path="+path;
}
+html (same as above):
<iframe id="frame" style="display:none"></iframe>
download
+php (the reason my its more or less working):
header("Content-Type: application/octet-stream");
header("Content-Disposition: attachment; filename=".$_GET['path']);
readfile($_GET['path']);
This solution doesn't wait for a click from me and starts the download by starting the site.
A working solution I thought about would be to link to another site where the download automatically starts but its absolutely not how it have to be. I use $_POST variables on the site and I lose them when I leave the site and I can't come back after the download.
It must start the download by clicking on the filename.
You can download straight from the anchor tag by using the 'download' attribute.
<a href="dateiupload/testmove.txt" download>Download</a>
The filename of the downloaded file will be testmove.txt by default.
You can change the filename like this.
Download
More Details at w3Schools
You were correct to use those headers - as you can see, the file is being downloaded. The only problem now is to have it download when you want it to.
For a very simple solution, I would suggest setting up a download.php file that will be the page you download all files from. You would setup a GET parameter for this file and the URL would look something like this:
http://your-cool-site.com/download.php?filename=textmove.txt
Now inside download.php, you'll read that GET parameter which will be a filename, and then pass it eventually to the readfile function. This is the stage that you should think about enforcing some level of security as passing a path directly to the function could give people access to files that they shouldn't be looking at! Think about limiting the actual downloadable files to a limited selection of files or paths you know to be "safe" for people to download.
You'll also need to use the file name in the headers (and possibly even the size of the file to support displaying progress of the download).
Once you have this download.php file ready, you can place links to it from other pages in a very similar way that you have now:
Download File
Clicking on this link will make the request to download.php and when it gets the appropriate headers, the download will start.

Start file download by client from Javascript call in C#/ASP.NET page?

I need to initiate file download from ASP.NET page from javascript code.
What would be my best option? Is it possible to call a webservice to do so, or somehow call usual event handler of C# page?
Note that I will retrieve a large amount of data, many megabytes.
You can use a hidden IFRAME element and initiate a file download request, which does give the feeling for a AJAX file download.
While the file is being downloaded you can do other activity in your form on client side.
Yes you can call a webservice or aspx page or http handler as well in this URL
function dowloadFileJS() {
// Create an IFRAME.
var iframe = document.createElement("iframe");
// Point the IFRAME to GenerateFile
iframe.src = "GenerateFile.aspx?yourQueryString=myQueryString";
// This makes the IFRAME invisible to the user.
iframe.style.display = "none";
// Add the IFRAME to the page. This will trigger a request to GenerateFile now.
document.body.appendChild(iframe);
}
You can use Javascript to create an iframe to the file you want to download. Have a look at this answer: Starting file download with JavaScript

How to save $(document).html() to a .xml file in jQuery or JavaScript?

I'm trying to push a form button and save all the html in the document to a xml file. Also If I have 3 frames or iFrames, I want to also save everything from my 2nd iframe id 'iframe2' (except the iframe itself) into a file, but have a dialog box pop up that says are you sure you want to save this file?
I'm not sure if this is possible, but if it is it would save me a step of writing xml to a file as well as displaying it in the browser. If its not possible in html4.01 is it possible in html5?
I can look at the html using $('#iframe2').html(); but not sure how to save it.
Thanks
There are 3 ways to do this as far as I know:
You could use Flash or Java or another browser plugin to make a save file dialog (check out Downloadify)
You could use data URIs (check out this answer. You'll want to change the mime type to application/xml)
You could use the server to trigger an attachement download with the contents you want. That content could be transmitted through AJAX (check out this question).
You can probably use a backend language like PHP to accept the string as POST data and write it to an XML file in one swoop.
if (window.confirm('Are you sure you want to save this file?')) {
$.post('/save.php', { 'html': $('#iframe2').html() }, function (_dta) {
window.alert(_dta);
});
}
and on PHP
<?php
$html = $_POST['html'];
file_put_contents('./iframe2.xml', $html);
echo 'saved!';
?>

starting file download with JavaScript

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 () { } );

Categories