printing iframe content with jquery - javascript

i have an iframe:
<iframe name="printarea" id="printarea" src="print.php" style="display: none;"></iframe>
i need this iframe to have the style "display: none;" so it is invisible
now when someone clicks a link generated via php:
echo '<img src="images/icon-print.png" alt="" />';
i want it to simply change the iframe SRC and print what is in the iframe, however my code is not working at all:
function print_receipt (id)
{
$('#printarea').attr('src', 'print.php?id='+id);
$('#printarea').focus();
$('#printarea').print();
}
so this is what i want:
- user clicks on link
- iframe content changes based on the link he clicks
- iframe content prints

2 issues:
you'll maybe need to wait until the page is loaded
print() is a method of window-objects
$('#printarea')
.load(function(){this.contentWindow.print();$(this).unbind('load');})
.attr('src', 'print.php?id='+id);

What is $('#printarea').focus(); supposed to achieve? As far as I know .focus() works with form elements and links...
What is $('#printarea').print();? Haven't come across that function in jQuery. If you're using a plugin it would help to mention which one.
So perhaps you'll have more luck with:
function print_receipt (id)
{
$('#printarea')
.attr('src', 'print.php?id='+id)
.css("display","block");
}

Related

Print function only works after second click

I have this function to print a DIV.
Whenever the page is loaded and I click in a "Print" link I have, the DIV is shown to be printed without CSS.
If I close Chrome's print visualization page and click in the "Print" link again, the DIV has CSS applied.
Any ideas why?
Javascript
function printDiv(divId) {
var printDivCSSpre =
'<link href="/static/assets/vendor/sb-admin-2-1.0.7/bower_components/bootstrap/dist/css/bootstrap.min.css" rel="stylesheet">' +
'<link href="/static/assets/vendor/sb-admin-2-1.0.7/dist/css/sb-admin-2.css" rel="stylesheet">' +
'<div style="width:1000px; padding-right:20px;">';
var printDivCSSpost = '</div>';
$('body').append('<iframe id="print_frame" name="print_frame" width="0" height="0" frameborder="0" src="about:blank"></iframe>');
$("link").clone().appendTo($("#print_frame").contents().find("head"));
window.frames["print_frame"].document.body.innerHTML =
printDivCSSpre + document.getElementById(divId).innerHTML + printDivCSSpost;
window.frames["print_frame"].window.focus();
var windowInstance = window.frames["print_frame"].window;
windowInstance.print();
}
HTML
<a id="print" href="#">
<i class="fa fa-print"></i> Print
</a>
<script>
$('#print').click(function () {
printDiv('report')
})
</script>
<div id="report" class="report">
<p># Generated Table#</p>
</div>
First click:
http://imgur.com/a/Go81Y
Closing the print preview page and clicking again in print
http://imgur.com/a/SCxJF
This happens because when you call your printDiv() function, css is also written using inner HTML and in this scenario CSS is not applied during first click because you wrote CSS to the elements even when they do not exist inside DIV.
The function to work as desired has to write DIV contents first and then CSS should be applied. I would say write css after contents of DIV or load on top of your HTML page and just write DIV contents.
Hope that helps.
Every thing is right just change the sequence. In browser debugger on first click it didn't show 'print_frame' in sources section while in second click it does (I am using chrome devtool).
So load in memory frame with css attributes during onload:
var windowInstance;
$(function(){
$('body').append('<iframe id="print_frame" name="print_frame" width="0" height="0" frameborder="0" src="about:blank"></iframe>');
$("link").clone().appendTo($("#print_frame").contents().find("head"));
windowInstance = window.frames["print_frame"].window;
});
and onClick just append html
$('#print').click(function () {
var divId = 'report';
var printDivCSSpre ='<div id="printReportDiv" style="width:1000px; padding-right:20px;">';
var printDivCSSpost = '</div>';
window.frames["print_frame"].document.body.innerHTML = printDivCSSpre + document.getElementById(divId).innerHTML + printDivCSSpost;
window.frames["print_frame"].window.focus();
windowInstance.print();
});
updated jsfiddle
Try this one. The problem mainly arises because the css has not been applied to the page when the print command is initiated. setTimeout is one way to solve it as others have mentioned but it is really not possible to predict how much delay you will need. Slow internet connections will require high delays before you fire the print statement. The following code, however, only fires the print event after the css has been properly applied to the iframe.
$('#print').click(function () {
if($("#print_frame").length == 0) {
$('#report').after('<iframe id="print_frame" name="print_frame" width="0" height="0" frameborder="0" src="about:blank"></iframe>');
}
var $head = $("#print_frame").contents().find("head");
// for now for ease I will just empty head
// ideally you would want to check if this is not empty
// append css only if empty
$head.empty();
$.ajax({
url : "https://dl.dropboxusercontent.com/u/7760475/reports.css",
dataType: "text",
success : function (reports) {
// grab css and apply its content to the iframe document
$head.append('<style>'+reports+'</style>');
$.ajax({
url : "https://dl.dropboxusercontent.com/u/7760475/bootstrap.css",
dataType: "text",
success : function (bootstrap) {
// grab another css and apply its content to the iframe document
// there may be better ways to load both css files at once but this works fine too
$head.append('<style>'+bootstrap+'</style>');
// css has been applied
// clone your div and print
var $body = $("#print_frame").contents().find('body');
// empty for ease
// but later append content only if empty
$body.empty();
$("#report").clone().appendTo($body);
$('#print_frame').get(0).contentWindow.print();
}
});
}
});
});
Use inline CSS instead.
Reason: When we PRINT or save as PDF if fails to fetch external css Files, So we have to use Inline css.
edited your file please see: jsfiddle.net/ytzcwykz/18/
As other people mentioned it is hard to see your problem without seeing the working example of a problem, but just guessing from the code:
Browser is not able to load the CSS before your print() call.
Browser is not able to render the CSS before your print() call.
Keeping that in mind changing your JS function that way might do the trick
function printDiv(divId) {
$("link").clone().appendTo($("#print_frame").contents().find("head"));
window.frames["print_frame"].document.body.innerHTML =
printDivCSSpre + document.getElementById(divId).innerHTML + printDivCSSpost;
window.frames["print_frame"].window.focus();
var windowInstance = window.frames["print_frame"].window;
setTimeout(function() {
windowInstance.print();
}, 0);
}
The idea behind this function is to let browser execute it's code after we added changed the HTML/CSS code in the window - see Why is setTimeout(fn, 0) sometimes useful?
WARNING: this approach is not tested for your particular problem, and it might also not work because we escape/leave the mouse-click call-stack, calling print() method might be not possible out of user-interaction stack.
UPDATE: after looking in the posted jsfiddle - my assumption was correct, the browser needs some time to load and render the CSS, that is why calling the print() right after changing iframe contents doesn't give the desired result. There are 3.5 ways to solve that:
Use events to identify when iframe's document and window has finished loading and rendering. I tried two approaches, and failed so far, need to read docs more carefully about when document and window are behiving during the loading sequence:
we can do that from outside of iframe, i.e. listen to events of iframe element and it's children
we can do that from inside of iframe, i.e. add little javascript snippet inside which will send a message to the parent window when loading is done.
Consider forming the print result different, how about print style-sheets? I.e. add one more style sheet with print-media query to the parent doc and just call print on it?
Consider forming an iframe which is already loaded and ready to be printed, but replace just the table contents inside it.
As others mentioned, The problem here is that the CSS files used are external resources and browser takes time to download and cache it locally. Once it is cached, it would serve faster and that's why it works fine from the second click.
As Anton mentioned, setTimeout is the key here! You may probably increase the timeout seconds to make that work. I tried setting it to 500ms and that worked,
setTimeout(function(){windowInstance.print();},500);

Get Isotope to not load specific images at all

I'm working with Isotope and I have a lot of images in it.
The problem is that when visiting my one page website from a smartphone it takes quite a bit to load the page as isotope load all the images thumbnails as soon as isotope itself loads.
So, basically I want to hide/not load all the images that mustn't be shown if it's category isn't clicked and what I did was use two workarounds:
set the figure to display:none so that it doesn't show the void where it was supposed to be and the other images can actually occupy that space
set the img src to about:blank so that it doesn't load until it's category is clicked
then when the link "Click me!"(category) is clicked the figure gets set to display:block and the img src gets replaced by the real image path.
style:
#showfigure{
display:none; !important
}
body:
Click me!
<figure id="showfigure" class="filter imgtoshow">
<img id="showimg" src="about:blank" alt="">
</figure>
script:
<script>
function showAll() {
document.getElementById("showfigure").style.display = 'block';
$("#showimg").attr("src","example.jpg");
};
</script>
Now, the only way I got it to work with multiple figures/images was giving each figure and image it's own id (showfigure1, showfigure2, showfigure3 etc... and showimg1, showimg2, showimg3, etc...) as using the same id only works for the first figure/img in the code.
Am I missing something?
I tried replacing the path of the img src like this:
http://jsfiddle.net/F6Gds/28/
But I can't get it to do the same with the onclick function from the link "Click me!", and anyways there's the same problem with the ids.
Thanks in advance for any help!

Targeting an iframe with Js/jQuery BEFORE the DOM loads

In order to prevent an iframe from flashing, I'm setting its visibility inside a setTimeout (the CSS is set to visibility:hidden)
setTimeout(function(){
$n('#myFrame').css('visibility','visible');}, 750);
Works great, although when I load subsequent locations inside the frame, the flashing behavior returns since the visibility is already set.
What I'd like to do is create a function that targets the iframe BEFORE the DOM/page has loaded to set the visibility to hidden again and then setTimeout.
Keep in mind that this script will run on the ServiceNow platform, meaning some options are limited (can't load in document head, etc.)
It's sort of like a reverse document.ready(). Is this even possible?
Thanks for any leads,
Paco
Just set it in your source:
<iframe style="display: none;"></iframe>
Then un-hide it when you want to.
$('buttonToChangeTheIframePage').click(function(e){
e.preventDefault();
$('#myFrame').css('visibility','hidden');
$('#myFrame').delay(1000).css('visibility','visible');
});
This assumes you are loading locations from OUTSIDE the iframe - anything within the iframe (like a link) will still trigger this behaviour.
EDIT
This is actually better and will work for all circumstances (I think - just check no silly errors as not tested)
<iframe id="myFrame" src="http://www.google.com/" onLoad="hideUnhide();"></iframe>
function hideUnhide(){
$('#myFrame').css('visibility','hidden').delay(1000).css('visibility','visible');
}
Use addAfterPageLoadedEvent(func) in js_include_doc_type.js
<iframe id="gsft_main" style="visibility: hidden;">
anything ....
<script>
addAfterPageLoadedEvent(function() {
$j('#gsft_main').css('visibility','visible');
});
</script>
</iframe>

Load a page via .load in pop-up

I'm trying to load a PHP page via jQuery. I want it to have a pop-up effect. I tried using the code below, but when the click event is triggered, it seems as if only the CSS from the imported page is being imported. The page content does not appear, but the look changes due to CSS conflicts.
I'd like the page to load and not conflict with the other CSS
function previewPop(){
$(".pop").click(function(){
$("iframe#preview").load("templates/1.php",
function(){$("iframe#preview").fadeIn(300); })
});
};
<div id="frame_wrapper">
</div>
$(".pop").click(function(){
var the_iframe = '<iframe id="my_iframe" src="' + templates/1.php + '" height="500px" width="500px">';
$('#frame_wrapper').append(the_iframe);
});
I hate dealing with iframes, so sometimes it's just easier to create a new one and destroy it as necessary.

How to store iframe in a variable?

<html>
<body>
<iframe id="src">
</body>
</html>
I want to have the iframe show up in the div element through a Javascript function but I can't seem to figure out what isn't working. Any ideas?
document.getElementById('site').src = http://www.w3schools.com/;
Thanks in advance!
Try
document.getElementById('src').src = 'http://www.w3schools.com/';
a) the url should be provided as string (quoted)
b) the id of your iframe is src not site
Your iframe don't have the id site, so your code won't have any effect.
(Also please note that you didn't close the iframe tag) .
Here's the right code (fiddle) .
<input type="button" onclick="changeIframeSrc('myFrame');" value="changeSrc">
<iframe src="http://www.example.com" id="myFrame"></iframe>
<script>
function changeIframeSrc(id) {
e = document.getElementById(id);
e.src = "http://www.wikipedia.com/";
}
</script>
First, a couple small things:
the id on your iframe appears to be src and not site; and
you need to close the iframe tag.
Assuming that you're just dealing with one iframe and it has an id then by all means:
var myIframe = document.getElementById('src');
// gives you just that one iframe element
You may want to consider document.querySelectorAll though, in case you're working with more than one iframe.
var iframes = document.querySelectorAll('iframe');
See that in action: http://jsbin.com/equzey/2/edit
And important side note: if all you need is access to the iframe element (e.g., to manipulate its source or to apply CSS via the style attribute) then the above should be fine. However, if you need to work with the contents of the iframe, you'll need to get inside its web page context with the contentWindow property:
var iframes = document.querySelectorAll('iframe');
iframes[0].contentWindow;

Categories

Resources