[javascript] Twitter Bootstrap: Print content of modal window

I'm developing a site using Bootstrap which has 28 modal windows with information on different products. I want to be able to print the information in an open modal window. Each window has an id.

<!-- firecell panel & radio hub -->
           <div class="modal hide fade" id="fcpanelhub">
              <div class="modal-header">
                <button type="button" class="close" data-dismiss="modal">X</button>
                <h3>5000 Control Panel & Radio Hub</h3>
              </div>
              <div class="modal-body">
                <img src="../site/img/firecell/firecell-panel-info-1.png" alt=""/><hr/>
                <img src="../site/img/firecell/firecell-panel-info-2.png" alt=""/><hr/>
                <img src="../site/img/firecell/firecell-radio-hub-info-1.png" alt=""/><hr/>
                <img src="../site/img/firecell/firecell-radio-hub-info-2.png" alt=""/>
              </div>
              <div class="modal-footer">
                <a href="#" class="btn" data-dismiss="modal">Close</a>
              </div>    
           </div>

So if I add in a new button in modal-footer - 'print', and it's clicked I want that modal to print. Would I be right in saying javascript would be used? If so, how do I tell javascript to print only the open modal, and not the others?

All help appreciated.

This question is related to javascript printing twitter-bootstrap modal-dialog

The answer is


you can download printThis lib from this source https://github.com/jasonday/printThis/blob/0a7f799693af8a8303bf0b8df0efc80c2694af81/printThis.js and include it into your html page

Call the following jquery to print all the content including the content that is not viewable. You may include your css files in an array if you have multiple css files.

$("#modalDiv").printThis({ 
    debug: false,              
    importCSS: true,             
    importStyle: true,         
    printContainer: true,       
    loadCSS: "../css/style.css", 
    pageTitle: "My Modal",             
    removeInline: false,        
    printDelay: 333,            
    header: null,             
    formValues: true          
}); 

I would suggest you try this jQuery plugin print element

It can let you just print the element you selected.


Here's an option using a JQuery extension I made based on the code by waspinator in the comments of the accepted answer:

jQuery.fn.extend({
    printElem: function() {
        var cloned = this.clone();
        var printSection = $('#printSection');
        if (printSection.length == 0) {
            printSection = $('<div id="printSection"></div>')
            $('body').append(printSection);
        }
        printSection.append(cloned);
        var toggleBody = $('body *:visible');
        toggleBody.hide();
        $('#printSection, #printSection *').show();
        window.print();
        printSection.remove();
        toggleBody.show();
    }
});

$(document).ready(function(){
    $(document).on('click', '#btnPrint', function(){
        $('.printMe').printElem();
    });
});

JSFiddle: http://jsfiddle.net/95ezN/1227/

This can be useful if you don't want to have this applied to every single print and just do it on your custom print button (which was my case).


This is a revised solution that will also work for modal windows rendered using a Grails template, where you can have the same modal template called multiple times (with different values) in the same body. This thread helped me immensely, so I thought I'd share it in case other Grails users found their way here.

For those who are curious, the accepted solution didn't work for me because I am rendering a table; each row has a button that opens a modal window with more details about the record. This led to multiple printSection divs being created and printed on top of each other. Therefore I had to revise the js to clean up the div after it was done printing.

CSS

I added this CSS directly to my modal gsp, but adding it to the parent has the same effect.

<style type="text/css">
   @media screen {
        #printSection {
           display: none;
        }
   }

   @media print {
        body > *:not(#printSection) {
           display: none;
        }
        #printSection, #printSection * {
            visibility: visible;
        }
        #printSection {
            position:absolute;
            left:0;
            top:0;
        }
   }
</style>

Adding it to the site-wide CSS killed the print functionality in other parts of the site. I got this from ComFreak's accepted answer (based on Bennett McElwee answer), but it is revised using ':not' functionality from fanfavorite's answer on Print <div id=printarea></div> only? . I opted for 'display' rather than 'visibility' because my invisible body content was creating extra blank pages, which was unacceptable to my users.

js

And this to my javascript, revised from ComFreak's accepted answer to this question.

function printDiv(div) {    
    // Create and insert new print section
    var elem = document.getElementById(div);
    var domClone = elem.cloneNode(true);
    var $printSection = document.createElement("div");
    $printSection.id = "printSection";
    $printSection.appendChild(domClone);
    document.body.insertBefore($printSection, document.body.firstChild);

    window.print(); 

    // Clean up print section for future use
    var oldElem = document.getElementById("printSection");
    if (oldElem != null) { oldElem.parentNode.removeChild(oldElem); } 
                          //oldElem.remove() not supported by IE

    return true;
}

I had no need for appending elements, so I removed that aspect and changed the function to specifically print a div.

HTML (gsp)

And the modal template. This prints the modal header & body and excludes the footer, where the buttons were located.

<div class="modal-content">
    <div id="print-me"> <!-- This is the div that is cloned and printed -->
        <div class="modal-header">
            <!-- HEADER CONTENT -->
        </div>
        <div class="modal-body">
             <!-- BODY CONTENT -->
        </div>
    </div>
    <div class="modal-footer">
                                 <!-- This is where I specify the div to print -->
        <button type="button" class="btn btn-default" onclick="printDiv('print-me')">Print</button>
        <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
    </div>
</div>

I hope that helps someone!


With the currently accepted solution you cannot print the page which contains the dialog itself anymore. Here's a much more dynamic solution:

JavaScript:

$().ready(function () {
    $('.modal.printable').on('shown.bs.modal', function () {
        $('.modal-dialog', this).addClass('focused');
        $('body').addClass('modalprinter');

        if ($(this).hasClass('autoprint')) {
            window.print();
        }
    }).on('hidden.bs.modal', function () {
        $('.modal-dialog', this).removeClass('focused');
        $('body').removeClass('modalprinter');
    });
});

CSS:

@media print {
    body.modalprinter * {
        visibility: hidden;
    }

    body.modalprinter .modal-dialog.focused {
        position: absolute;
        padding: 0;
        margin: 0;
        left: 0;
        top: 0;
    }

    body.modalprinter .modal-dialog.focused .modal-content {
        border-width: 0;
    }

    body.modalprinter .modal-dialog.focused .modal-content .modal-header .modal-title,
    body.modalprinter .modal-dialog.focused .modal-content .modal-body,
    body.modalprinter .modal-dialog.focused .modal-content .modal-body * {
        visibility: visible;
    }

    body.modalprinter .modal-dialog.focused .modal-content .modal-header,
    body.modalprinter .modal-dialog.focused .modal-content .modal-body {
        padding: 0;
    }

    body.modalprinter .modal-dialog.focused .modal-content .modal-header .modal-title {
        margin-bottom: 20px;
    }
}

Example:

<div class="modal fade printable autoprint">
  <div class="modal-dialog">
    <div class="modal-content">
      <div class="modal-header">
        <button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
        <h4 class="modal-title">Modal title</h4>
      </div>
      <div class="modal-body">
        <p>One fine body&hellip;</p>
      </div>
      <div class="modal-footer">
        <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
        <button type="button" class="btn btn-primary" onclick="window.print();">Print</button>
      </div>
    </div><!-- /.modal-content -->
  </div><!-- /.modal-dialog -->
</div><!-- /.modal -->

I was facing two issues Issue 1: all fields were coming one after other and Issue 2 white space at the bottom of the page when used to print from popup.

I Resolved this by

making display none to all body * elements most of them go for visibility hidden which creates space so avoid visibility hidden

    @media print {
        body * {
           display:none;
        width:auto;
        height:auto;
        margin:0px;padding:0px; 
        }
        #printSection, #printSection * {
            display:inline-block!important;
        }
        #printSection {
            position:absolute;
            left:0;
            top:0;  
            margin:0px; 
            page-break-before: none;
            page-break-after: none;
            page-break-inside: avoid;      
        }
#printSection .form-group{

      width:100%!important;
      float:left!important;
      page-break-after: avoid;
    }
#printSection label{
        float:left!important;
        width:200px!important;
        display:inline-block!important;
      }

#printSection .form-control.search-input{
        float:left!important;
        width:200px!important;
        display: inline-block!important;
      }
}

_x000D_
_x000D_
@media print{_x000D_
 body{_x000D_
  visibility: hidden; /* no print*/_x000D_
 }_x000D_
 .print{_x000D_
  _x000D_
  visibility:visible; /*print*/_x000D_
 }_x000D_
}
_x000D_
<body>_x000D_
  <div class="noprint"> <!---no print--->_x000D_
  <div class="noprint"> <!---no print--->_x000D_
  <div class="print">   <!---print--->_x000D_
  <div class="print">   <!---print--->_x000D_
_x000D_
_x000D_
</body>
_x000D_
_x000D_
_x000D_


Heres a solution with no Javascript or plugin - just some css and one extra class in the markup. This solutions uses the fact that BootStrap adds a class to the body when a dialog is open. We use this class to then hide the body, and print only the dialog.

To ensure we can determine the main body of the page we need to contain everything within the main page content in a div - I've used id="mainContent". Sample Page layout below - with a main page and two dialogs

<body>
 <div class="container body-content">

  <div id="mainContent">
       main page stuff     
  </div>
  <!-- Dialog One -->
  <div class="modal fade in">
   <div class="modal-dialog">
    <div class="modal-content">
          ...
    </div>
   </div>
  </div>

  <!-- Dialog Two -->
  <div class="modal fade in">
   <div class="modal-dialog">
    <div class="modal-content">
          ...
    </div>
   </div>
  </div>

 </div>
</body>

Then in our CSS print media queries, I use display: none to hide everything I don't want displayed - ie the mainContent when a dialog is open. I also use a specific class noPrint to be used on any parts of the page that should not be displayed - say action buttons. Here I am also hiding the headers and footers. You may need to tweak it to get exactly want you want.

@media print {
    header, .footer, footer {
        display: none;
    }

    /* hide main content when dialog open */
    body.modal-open div.container.body-content div#mainContent {
        display: none;
    }

    .noPrint {
        display: none;
    }
}

I just use a bit of jQuery/javascript:

html:

<h1>Don't Print</h1>

<a data-target="#myModal" role="button" class="btn" data-toggle="modal">Launch modal</a>

<div class="modal fade hide" id="myModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel"      aria-hidden="true">
  <div class="modal-header">
    <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
     <h3 id="myModalLabel">Modal to print</h3>
  </div>
  <div class="modal-body">
    <p>Print Me</p>
  </div>
  <div class="modal-footer">
    <button class="btn" data-dismiss="modal" aria-hidden="true">Close</button>
    <button class="btn btn-primary" id="printButton">Print</button>
  </div>
</div>

js:

$('#printButton').on('click', function () {
    if ($('.modal').is(':visible')) {
        var modalId = $(event.target).closest('.modal').attr('id');
        $('body').css('visibility', 'hidden');
        $("#" + modalId).css('visibility', 'visible');
        $('#' + modalId).removeClass('modal');
        window.print();
        $('body').css('visibility', 'visible');
        $('#' + modalId).addClass('modal');
    } else {
        window.print();
    }
});

here is the fiddle


Examples related to javascript

need to add a class to an element How to make a variable accessible outside a function? Hide Signs that Meteor.js was Used How to create a showdown.js markdown extension Please help me convert this script to a simple image slider Highlight Anchor Links when user manually scrolls? Summing radio input values How to execute an action before close metro app WinJS javascript, for loop defines a dynamic variable name Getting all files in directory with ajax

Examples related to printing

How do I print colored output with Python 3? Print a div content using Jquery Python 3 print without parenthesis How to find integer array size in java Differences Between vbLf, vbCrLf & vbCr Constants Printing variables in Python 3.4 Show DataFrame as table in iPython Notebook Removing display of row names from data frame Javascript window.print() in chrome, closing new window or tab instead of cancelling print leaves javascript blocked in parent window Print a div using javascript in angularJS single page application

Examples related to twitter-bootstrap

Bootstrap 4: responsive sidebar menu to top navbar CSS class for pointer cursor How to install popper.js with Bootstrap 4? Change arrow colors in Bootstraps carousel Search input with an icon Bootstrap 4 bootstrap 4 responsive utilities visible / hidden xs sm lg not working bootstrap.min.js:6 Uncaught Error: Bootstrap dropdown require Popper.js Bootstrap 4 - Inline List? Bootstrap 4, how to make a col have a height of 100%? Bootstrap 4: Multilevel Dropdown Inside Navigation Read input from a JOptionPane.showInputDialog box Disable click outside of angular material dialog area to close the dialog (With Angular Version 4.0+) How can I display a modal dialog in Redux that performs asynchronous actions? Angular 2.0 and Modal Dialog How to use Bootstrap modal using the anchor tag for Register? Bootstrap modal opening on page load Trying to make bootstrap modal wider How to present a modal atop the current view in Swift Send parameter to Bootstrap modal window? Set bootstrap modal body height by percentage