javascript nullifies when setting the document.body.innerHTML - javascript

Good day.
I am currently working on a project that prints a desired <div> to a printer.
Here is the code:
var printContents = document.getElementById(id).innerHTML;
var originalContents = document.body.innerHTML;
document.body.innerHTML = printContents;
document.body.style.display = "none";
window.print();
document.body.innerHTML = originalContents;
document.body.style.display = "block";
This code works and prints the desired <div>, but after that I need to put back the previous page again so I used this statement:
document.body.innerHTML = originalContents;
document.body.style.display = "block";
This displays the previous page but the functionalities of my buttons are gone?! Can someone explain to me what happened and is there a solution to this problem? Thanks in advance!

This is happening because you've wiped out the old DOM which had events wired up to it, and replaced it with a totally new, different DOM that just happens to have the same HTML.
Presumably you're taking this approach because the printable zone is determined at runtime. A less-destructive solution might be to create a new <iframe> and copy the desired markup into that; then invoke print() on the iframe. Something like:
var printElement = function(element) {
var frame = document.createElement('iframe');
document.appendChild(frame);
frame.contentDocument.innerHTML = element.innerHTML;
frame.contentWindow.print();
document.removeChild(frame);
};
You'll also need to copy over any CSS references into the <iframe>.
(note this is pseudo-code and not tested)

Your code clears the document and then puts back the HTML stored in originalContents, but this variable stores only a string, so all previously registered event handlers are gone.
Why don't you create a print stylesheet and hide everything except the content that you want to print?
<link rel="stylesheet" type="text/css" href="print.css" media="print">

When you reset the innerHTML, you don't get all your event handlers back. They are wiped out when you create entirely new DOM elements.
One idea would be to have two master divs in the body, one that is your normal display and one that is what you want to print. You can then hide whichever one you don't want to display like this:
<body>
<div id="mainContent">main screen content goes here</div>
<div id="printContent">generated print content goes here</div>
</body>
// hide main content
var mainDiv = document.getElementById("mainContent");
mainDiv.style.display = "none";
// put content to print in the print div and show it
var printDiv = document.getElementById("printContent");
printDiv.innerHTML = document.getElementById(id).innerHTML;
printDiv.style.display = "block";
// print
window.print();
// restore visibility
mainDiv.style.display = "block";
printDiv.style.display = "none;
You could also just use the whole body for printing and use a stylesheet with media="print" to control the visibility of the things you do/don't want to print.

You can add a click event to all dives inside your page so that user can click the div.
after that add a class to that div which the class is defined within the print CSS file.
inside css print file use the following code:
`*{display:none}
.printableDiv{display:block}`
to define a print css file use this code :
<link rel="stylesheet" type="text/css" href="print.css" media="print"> (which Rafael has told you ).
good luck

Related

Does anyone know a way to print the loaded page HTML after DOM is completed?

I'm looking for a way to read the source code of a page after it finished loading and inspect the code to see if it contains a specific text.
I found this reference but this only returns the text visible in the page and not the whole HTML code.
For instance, if the html source code is:
<html>
<header>
<header>
<body>
<p> This is a paragraph</a>
<body>
</html>
I want the script to print exactly the same thing.
Your help is appreciated.
I think you are over-complicating this problem. You don't need to "print" the page's HTML or "inspect the code".
In a comment, you said:
Check if page contains an iframe [and] Display a message if the iframe is found
You can just use DOM traversal functions to examine the DOM.
Try something like this:
window.addEventListener('load', function() {
if(document.getElementsByTagName('iframe').length){
console.log('Found an iframe');
}
});
Or with jQuery:
$(function() {
if($('iframe').length){
console.log('Found an iframe');
}
});
That's so simple, you can use this method to run a script after a page is fully loaded window.onload
function load(){
console.log(document.getElementsByTagName('html')[0].innerHTML);
}
window.onload = load;
For further explanations, check this post
Do like this, call this function on load
Fiddle Demo
function printBody() {
// store oiginal content
var originalContents = document.body.innerHTML;
// get the outer html of the document element
document.body.innerText = document.documentElement.outerHTML;
// call window.print if you want it on paper
window.print();
// or put it into an iframe
// var ifr = document.createElement('iframe');
// ifr.src = 'data:text/plain;charset=utf-8,' + encodeURI(document.documentElement.outerHTML);
// document.body.appendChild(iframe);
// a small delay is needed so window.print does not get the original
setTimeout(function(){
document.body.innerHTML = originalContents;
}, 2000);
}
Src: Print <div id=printarea></div> only?
Assuming that by 'print' you don't actually mean to transfer it to a paper copy, you can add some script like:
window.addEventListener('load', function() {
var content = document.documentElement.innerHTML,
pre = document.createElement('pre'),
body = document.body;
pre.innerText = content;
body.insertBefore(pre, body.firstChild);
});
What this does, step by step is:
window.addEventListener('load', function() > Wait for the page to be fully loaded and then execute the function
content = document.documentElement.innerHTML > store the actual page source in the content variable (document.documentElement refers to the 'root'-node, usually <html> in html documents
pre = document.createElement('pre') > create a new <pre>-element
body = document.body > create a reference to the <body> element
pre.innerText = content > assign the HTML-structure we've stored earlier as text to the <pre>-element
body.insertBefore(pre, body.firstChild) > put the <pre>-element (now with contents) before any other element in the body (usually on top of the page).
This leaves you with the entire source (as it was before creating the <pre>-element containing the source) on top of you page.
Edit: Added <iframe> workflow
It was not clear to me you actually wanted to target an <iframe>, so here's how to do that (using a naive approach, more on that further on):
window.addEventListener('load', function() {
var iframeList = document.getElementsByTagName('iframe'),
body = document.body,
content, pre, i;
for (i = 0; i < iframeList.length; ++i) {
content = iframeList[i].documentElement.innerHTML;
pre = document.createElement('pre');
pre.innerText = content;
body.insertBefore(pre, body.firstChild);
}
});
why is this approach naive?
There is a thing called Same-Origin-Policy in javascript, which prevents you from accessing <iframe>-content which if the contents do not originate from the same domain as the page containing the <iframe>.
There are several ways to take this into consideration, you could wrap the inside of the for-loop in try/catch-blocks, though I prefer to use a more subtle approach by not even considering <iframes> which do not match the Same-Origin-Policy.
In order to do this, you can swap the getElementsByTagName method with the querySelectorAll method (please note the compatibility table at the bottom of that page, see if it matches your requirements).
The querySelectorAll accepts a valid CSS selector and will return a NodeList containing all matching elements.
A simple selector to use would be
'iframe[src]:not([src^="//"]):not(src^="http")' which selects all iframe with a src attribute which does not start with either // or http
Disclaimer: I never use a <base>-tag (which changes all relative paths within the HTML) or refer to the current website using a path containing the domain, so the example CSS-selector does not consider these aberrations.
Can you use :not()
IE9 or better
Can you use document.querySelector(All)
IE8 or better (in order to use with :not(), IE9 or better)
hover/click the boxes above to show the spoiler

Javascript overwrites data on screen and refreshes page

I have been working on a project that I just need to print the contents of a hidden div. The below solution works fine, but replaces the page contents with the div then calls the print of the window and then replaces the page with the original contents. This is fine, but when I click on the page after this or try to print again, the page refreshes.
Is there a way, without opening a new window to print the contents of a div and the page still be functional?
$scope.printDiv = function(printable) {
var restorePage = document.body.innerHTML;
var printContent = document.getElementById(printable).innerHTML;
document.body.innerHTML = "<html><head><title></title></head><body>" + printContent + "</body>";
window.print();
document.body.innerHTML = restorePage;
};
I had created a directive that did something much like this. It involves creating a new window, populating it with the HTML you want printed, printing that window, and then finally closing.
The code looks like the following:
$scope.printPage = function() {
var pageToPrint = $window.open('', 'Print Page', 'width=800, height=600');
pageToPrint.document.write(angular.element(pageHtml).html());
pageToPrint.document.close();
pageToPrint.focus();
pageToPrint.print();
pageToPrint.close();
}
This works in all of the browsers and cleanly closes everything out once the user finishes with the print dialog window.
You can do it with CSS: https://stackoverflow.com/a/356123/1516112
When the user click on your button, wrap your entire page inside a div using the .no-print class. Next add your content in another div next to the previous div. Call print() and restore your page. It should works.
See a similar question that I found: AJAX - Print Page Content
It seems the answer of Matt Razza is what You are looking for.
If you're trying to print invisible content you could use two
different css files for the different media (screen vs print) where
you hide/unhide the required content via display: none; and then
spawn the print dialog via window.print().
<link rel="stylesheet" type="text/css" href="theme1.css" media="screen" />
<link rel="stylesheet" type="text/css" href="theme2.css" media="print" />
<div class="hidden_on_page">YOU CAN'T SEE ME BUT YOU CAN PRINT ME!</div>
<div class="on_page">YOU CAN SEE ME BUT YOU CAN'T PRINT ME</div>
Then in theme1.css:
.hidden_on_page { display: none; }
theme 2.css:
.on_page { display: none; }
And you would trigger the print dialog to spawn when required via:
window.print();

Generate HTML-page dynamically using Javascript

I have a list of elements where I want the user to be able to print just the clicked element, and not the whole surrounding page. The elements looks as follows:
<div class="element" id="#element1">Element 1</div>
<div class="element" id="#element2">Element 2</div>
<div class="element" id="#element3">Element 3</div>
To be able to print just the element the user clicks, I use this code to fetch whatever element is clicked:
jQuery(document).ready(function($) {
$( '.element' ).click(function() {
var clickedEl = $(this).attr('id');
printDiv( clickedEl );
return false;
});
});
The id of the clicked element is then passed on to a function, creating a very simple HTML-page for print:
function printDiv(id) {
var printContents = document.getElementById(id).innerHTML;
var printContentsBefore = '<html><head>\
<link rel="stylesheet" href="/css/blabla_print.css" type="text/css" />\
</head><body><table><tr>';
var printContentsAfter = '</tr></table></body></html>';
var originalContents = document.body.innerHTML;
document.body.innerHTML = printContentsBefore + printContents + printContentsAfter;
//document.body.innerHTML = printContents;
window.print();
document.body.innerHTML = originalContents;
}
The code sort of works, but I'm having two problems:
The print window that pops up contains the data of the clicked element about half of the times. The other half the window is empty. How can that be, and how do I solve it?
In the generated page I'm trying to load a CSS-file to format the way the content looks, but without any luck. Is what I'm trying to do here at all possible, and if so how?
And in case it's relevant; the code is being used on a WordPress-based page.
Thanks!
I will never understand why people waste so much effort getting an element's ID, only to then use getElementById to get the element that they already had again...
$(".element").on("click",function() {
printDiv(this);
});
function printDiv(elem) {
var before = '...',
after = '...',
result = before + elem.innerHTML + after;
// now do stuff
}
It's worth noting that window.print() does not necessarily fire immediately. It's not synchronous. It just tells the browser that it should bring up the Print box. Therefore, resetting originalContents back on your content may or may not mess it up, as you have seen.
You may wish to have a "Cancel" button, styled with
#media print {
.cancelbutton {display:none}
}
Which does the actual reset.
Another note is that you are nuking the innerHTML of the page. Any event handlers that you may have will be completely annihilated, except on the body element itself. Just be aware of that.
Personally I would suggest a different method, one that would involve opening a new window/tab with just the content to be printed (you can open a window and document.write to it, for example).

Resize DIV with JavaScript to Fit on Page (To print)

So I'm trying to resize two Div's that I'd like to print.
Here's the function:
function printDiv(printMe) {
var printContents = document.getElementById(printMe).innerHTML + $('#printMe2').html();
var originalContents = document.body.innerHTML;
document.body.innerHTML = printContents;
window.print();
document.body.innerHTML = originalContents;
}
This function is being called with a button onClick.
There are Two Divs in total, One of them is a calendar, and the other one is a table. The size is a bit messed up tho. It looks like this:
Original DIV
Print Version:
I'm not so great with JavaScript, so I couldn't try too much. I've searched for relevant things, but sadly no (good) result.
Thanks in advance!
I would create a different css file for print, its much simpler then manipulating html with javascript. here is how you do it:
<link rel="stylesheet" href="print-style.css" type="text/css" media="print" />
or
#media print body {}
here is a good tutorial for print-css
http://edutechwiki.unige.ch/en/CSS_for_print_tutorial

Refresh a div on the same page after using click function

I'm using a JavaScript print function that print's the predefined div of a page on click. The function is as following:
<head>
<script type="text/javascript">
function printDiv(any printable div) {
var printContents = document.getElementById(any printable div).innerHTML;
var originalContents = document.body.innerHTML;
document.body.innerHTML = printContents;
window.print();
document.body.innerHTML = originalContents;
}
</script>
</head>
The printer form input method and printable div are as following:
<body>
<input type="button" class="button" onclick="printDiv('any printable div')" name="print" value="print" />
<div id = "any printable div"> On button click contents here are printed </div>
</body>
I'm also using a jQuery text marquee / scroller on the same page that performs it task based on the function:
$(document).ready(function(){
All works fine independently. The problem is that the text marquee / scroller stops scrolling the text when the print button is clicked. The scroller can't scroll the text until the page is refreshed. So I'm using html meta refresh but that may be an annoying experience to the visitors. I don't want to use the scroller in an iframe too.
I've tried some jQuery and JavaScript based solution by this time. The scripts refresh (Just fades in and out the whole block of texts) the div where the scroller is silently but actually can't keep the text scrolling.
Is there any good jQuery or JavaScript based solution available that refreshes the scroller div silently based on the situation I explained above in a given period of time?
You cannot have spaces in your variable name. function printDiv(any printable div) is a syntax error.
Try instead:
function printDiv(elId) {
var printContents = document.getElementById(elId).innerHTML;
var originalContents = document.body.innerHTML;
document.body.innerHTML = printContents;
window.print();
document.body.innerHTML = originalContents;
}
I assume from what you've stated that the intention here is to be able to print only a certain div, rather than an entire page. If that is the case then you are really going to extremes here to perform this function.
If you just want to make a prettier version of the page to print (one without menus, etc) look at How can I have different CSS when I print or print preview?. That question will show how to use a different set of css for printing, so you can set display:none; to anything that you don't want to display when printing.
If you want to print only a single div then you could look at the jQuery print element plugin. This is a simple js file that you link in your html then call
$([selector]).printElement();
to print just that element. Eg you could rewrite your method as so:
function printDiv(anyPrintableDiv) {
$('#' + anyPrintableDiv).printElement();
}

Categories

Resources