Reputation: 25583
The JavaScript code window.print() can print the current HTML page.
If I have a div in an HTML page (for example, a page rendered from an ASP.NET MVC view), then I want to print the div only.
Is there any jQuery unobtrusive JavaScript or normal JavaScript code to implement this request?
Making it more clear, suppose the rendered HTML page is like:
<html xmlns="http://www.w3.org/1999/xhtml">
<head id="Head" runat="server">
<title>
<asp:ContentPlaceHolder runat="server" ID="TitleContent" />
</title>
</head>
<body>
<div id="div1" class="div1">....</div>
<div id="div2" class="div2">....</div>
<div id="div3" class="div3">....</div>
<div id="div4" class="div4">....</div>
<div id="div4" class="div4">....</div>
<p>
<input id="btnSubmit" type="submit" value="Print" onclick="divPrint();" />
</p>
</body>
</html>
Then I want to click on the Print button, only printing div3.
Upvotes: 71
Views: 158837
Reputation: 43
I had a problem where input controls were loosing their values when printing so I cooked up this code. This series of functions allows you to print either some static HTML snippet or the contents of a particular node and preserves input values and features hiding selected elements with the class "hideToPrint" and features a callback to modify the HTML just for the print so you can change things in other ways without messing with the original node. The only downside of this I know of is that the body looks like what you are printing while the print dialog is up.
This has only been tested on Chrome.
CSS:
@media print {
.hideToPrint {
display: none;
}
}
JS:
/**
* Takes the outerHTML of the element referenced by contentId
* and applies the fnModifyHtml(printContents) to the
* outerHTML content if specified, and prints it.
* Any content element that has the class "hideToPrint" will
* be hidden for printing.
* @param {string} contentId host element id
* @param {function=} fnModifyHtml
*/
async function as_printContent(contentId, fnModifyHtml=null) {
const aHideToPrint = Array.from(document.getElementsByClassName('hideToPrint'));
aHideToPrint.forEach((el) => {
hide(el);
});
await as_printRawContent(ge(contentId), fnModifyHtml);
aHideToPrint.forEach((el) => {
show(el);
});
}
/**
* Asynchronously prints the raw content of an element.
*
* @param {Element|string} elContent - The element or HTML string to print.
* @param {function} fnModifyHtml - A function to modify the printed HTML.
* @return {Promise<void>} A promise that resolves when the printing is done.
*/
async function as_printRawContent(elContent, fnModifyHtml = null) {
if (typeof(elContent) == 'string') {
// this is HTML and needs to be placed into a temporary element
const html = elContent;
elContent = document.createElement('div');
elContent.innerHTML = html;
}
const aBodyValues = saveNodeValues(document.body);
const bodyHTML = document.body.innerHTML;
const aPrintContentValues = saveNodeValues(elContent);
let printContents = elContent.outerHTML;
if (fnModifyHtml) {
printContents = fnModifyHtml(printContents);
}
document.body.innerHTML = printContents;
restoreNodeValues(document.body, aPrintContentValues);
await delay(1);
window.print();
document.body.innerHTML = bodyHTML;
restoreNodeValues(document.body, aBodyValues);
addEventHandlers();
}
/**
* Retrieve the values of all input, select, and textarea elements within a given node.
*
* @param {HTMLElement} node - The node to search for input elements.
* @return {Array} An array of objects containing the id, value, and type of each input element.
*/
function saveNodeValues(node) {
return Array.from(node.querySelectorAll('input, select, textarea')).map((el) => {
if (!el.id) {
console.assert(el.id, `Element ${el.outerHTML} has no id`);
}
return {
id: el.id,
value: (el.type == 'checkbox') ? el.checked : el.value,
type: el.type
};
});
}
/**
* Restores the values of the specified DOM elements based on the provided array of values.
*
* @param {Node} node - The root node from which the DOM elements will be searched.
* @param {Array} aValues - An array of objects containing the id, value, and type of each element to be restored.
* @param {string} aValues[].id - The id of the DOM element.
* @param {any} aValues[].value - The value to be restored on the DOM element.
* @param {string} aValues[].type - The type of the DOM element (e.g., 'checkbox', 'text', etc.).
*/
function restoreNodeValues(node, aValues) {
aValues.forEach(({ id, value, type }) => {
const el = ge(id);
if (el) {
if (type === 'checkbox') {
el.checked = value ? 'checked' : '';
} else {
el.value = value;
}
}
});
}
/**
* Delays the execution of subsequent code for a specified amount of time.
* @param {number} time The amount of time to delay in milliseconds.
* @returns {Promise} A promise that resolves after the specified time has passed.
*/
async function delay(time) {
return new Promise((resolve) => {
setTimeout(resolve, time);
});
}
Upvotes: 0
Reputation: 364
You could use jquery to do this.
$('#btnSubmit').click(function(){
var divContent = $("#div3").html();
var originalContents = $("body").html();
$("body").empty().html(divContent );
window.print();
$("body").html(originalContents);
})
Upvotes: 1
Reputation: 1489
<div id="invocieContainer">
<div class="row">
...Your html Page content here....
</div>
</div>
<script src="/Scripts/printThis.js"></script>
<script>
$(document).on("click", "#btnPrint", function(e) {
e.preventDefault();
e.stopPropagation();
$("#invocieContainer").printThis({
debug: false, // show the iframe for debugging
importCSS: true, // import page CSS
importStyle: true, // import style tags
printContainer: true, // grab outer container as well as the contents of the selector
loadCSS: "/Content/bootstrap.min.css", // path to additional css file - us an array [] for multiple
pageTitle: "", // add title to print page
removeInline: false, // remove all inline styles from print elements
printDelay: 333, // variable print delay; depending on complexity a higher value may be necessary
header: null, // prefix to html
formValues: true // preserve input/form values
});
});
</script>
For printThis.js souce code, copy and pase below URL in new tab https://raw.githubusercontent.com/jasonday/printThis/master/printThis.js
Upvotes: 8
Reputation: 490607
You could use a print stylesheet, but this will affect all print functions.
You could try having a print stylesheet externalally, and it is included via JavaScript when a button is pressed, and then call window.print()
, then after that remove it.
Upvotes: 4
Reputation: 413
Try this JavaScript code:
function printout() {
var newWindow = window.open();
newWindow.document.write(document.getElementById("output").innerHTML);
newWindow.print();
}
Upvotes: 12
Reputation: 1692
I would go about it somewhat like this:
<html>
<head>
<title>Print Test Page</title>
<script>
printDivCSS = new String ('<link href="myprintstyle.css" rel="stylesheet" type="text/css">')
function printDiv(divId) {
window.frames["print_frame"].document.body.innerHTML=printDivCSS + document.getElementById(divId).innerHTML;
window.frames["print_frame"].window.focus();
window.frames["print_frame"].window.print();
}
</script>
</head>
<body>
<h1><b><center>This is a test page for printing</center></b><hr color=#00cc00 width=95%></h1>
<b>Div 1:</b> <a href="javascript:printDiv('div1')">Print</a><br>
<div id="div1">This is the div1's print output</div>
<br><br>
<b>Div 2:</b> <a href="javascript:printDiv('div2')">Print</a><br>
<div id="div2">This is the div2's print output</div>
<br><br>
<b>Div 3:</b> <a href="javascript:printDiv('div3')">Print</a><br>
<div id="div3">This is the div3's print output</div>
<iframe name="print_frame" width="0" height="0" frameborder="0" src="about:blank"></iframe>
</body>
</html>
Upvotes: 120
Reputation: 8491
Along the same lines as some of the suggestions you would need to do at least the following:
An example CSS could be as simple as this:
@media print {
body * {
display:none;
}
body .printable {
display:block;
}
}
Your JavaScript would then only need to apply the "printable" class to your target div and it will be the only thing visible (as long as there are no other conflicting CSS rules -- a separate exercise) when printing happens.
<script type="text/javascript">
function divPrint() {
// Some logic determines which div should be printed...
// This example uses div3.
$("#div3").addClass("printable");
window.print();
}
</script>
You may want to optionally remove the class from the target after printing has occurred, and / or remove the dynamically-added CSS after printing has occurred.
Below is a full working example, the only difference is that the print CSS is not loaded dynamically. If you want it to really be unobtrusive then you will need to load the CSS dynamically like in this answer.
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8" />
<title>Print Portion Example</title>
<style type="text/css">
@media print {
body * {
display:none;
}
body .printable {
display:block;
}
}
</style>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"></script>
</head>
<body>
<h1>Print Section Example</h1>
<div id="div1">Div 1</div>
<div id="div2">Div 2</div>
<div id="div3">Div 3</div>
<div id="div4">Div 4</div>
<div id="div5">Div 5</div>
<div id="div6">Div 6</div>
<p><input id="btnSubmit" type="submit" value="Print" onclick="divPrint();" /></p>
<script type="text/javascript">
function divPrint() {
// Some logic determines which div should be printed...
// This example uses div3.
$("#div3").addClass("printable");
window.print();
}
</script>
</body>
</html>
Upvotes: 33