Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there an Angular way of printing a div from a HTML page?

I have an html page using AngularJS, and I want to print a div from it. Is there an Angular way of doing it? .. or it`s just the classic javascript way below:

    <script language="javascript" type="text/javascript">
    function printDiv(divID) {
        //Get the HTML of div
        var divElements = document.getElementById(divID).innerHTML;
        //Get the HTML of whole page
        var oldPage = document.body.innerHTML;

        //Reset the page's HTML with div's HTML only
        document.body.innerHTML =
        "<html><head><title></title></head><body>" +
        divElements + "</body>";

        //Print Page
        window.print();

        //Restore orignal HTML
        document.body.innerHTML = oldPage;
        }
    </script> 

If AngularJS doesn't have anything around this, can you suggest o way of doing it, without using JavaScript functions (ex: doc.getElementById() ).. an approach close to the AngularJS way ?

Thx,

like image 588
Ionut Ursan Avatar asked Oct 28 '13 14:10

Ionut Ursan


2 Answers

I have created a simple directive for printing div contents using the iframe technique. It's a bit hackish, but works very well. there is no better way to do it in my opinion. The directive script is:

'use strict';

angular.module('yourAppNameHere').directive('printDiv', function () {
  return {
    restrict: 'A',
    link: function(scope, element, attrs) {
      element.bind('click', function(evt){    
        evt.preventDefault();    
        PrintElem(attrs.printDiv);
      });

      function PrintElem(elem)
      {
        PrintWithIframe($(elem).html());
      }

      function PrintWithIframe(data) 
      {
        if ($('iframe#printf').size() == 0) {
          $('html').append('<iframe id="printf" name="printf"></iframe>');  // an iFrame is added to the html content, then your div's contents are added to it and the iFrame's content is printed

          var mywindow = window.frames["printf"];
          mywindow.document.write('<html><head><title></title><style>@page {margin: 25mm 0mm 25mm 5mm}</style>'  // Your styles here, I needed the margins set up like this
                          + '</head><body><div>'
                          + data
                          + '</div></body></html>');

          $(mywindow.document).ready(function(){
            mywindow.print();
            setTimeout(function(){
              $('iframe#printf').remove();
            },
            2000);  // The iFrame is removed 2 seconds after print() is executed, which is enough for me, but you can play around with the value
          });
        }

        return true;
      }
    }
  };
});

In your template you mark the print button like this:

<a href="#" print-div=".css-selector-of-the-div-you-want-to-print">Print!</a>

And that's it, it should work. The hackish part is that the iFrame is removed after a certain number of miliseconds as there is no cross-browser way to detect the end of the print execution, so you guestimate how much time would be needed for it to run.

You may need to include jQuery for it to work, I'm not sure as I almost never work without it. I added some inline comments to make things clearer. I used some code from this answer that uses a popup to print div content (but outside of Angular.js). Maybe you'll like that approach more.

like image 190
Mladen Danic Avatar answered Nov 15 '22 19:11

Mladen Danic


I needed this to work in IE8+

'use strict';

angular
.module('print-div', [])
.directive('printDiv', function () {
    return {
        restrict: 'A',
        link: function(scope, element, attrs) {

            var iframe;
            var elementToPrint = document.querySelector(attrs.printDiv);

            if (!window.frames["print-frame"]) {
                var elm = document.createElement('iframe');
                elm.setAttribute('id', 'print-frame');
                elm.setAttribute('name', 'print-frame');
                elm.setAttribute('style', 'display: none;');
                document.body.appendChild(elm);
            }

            function write(value) {
                var doc;
                if (iframe.contentDocument) { // DOM
                    doc = iframe.contentDocument;
                } else if (iframe.contentWindow) { // IE win
                    doc = iframe.contentWindow.document;
                } else {
                    alert('Wonder what browser this is... ' + navigator.userAgent);
                }
                doc.write(value);
                doc.close();
            }

            element.bind('click', function(event) {
                iframe = document.getElementById('print-frame');
                write(elementToPrint.innerHTML);

                if (window.navigator.userAgent.indexOf ("MSIE") > 0) {
                    iframe.contentWindow.document.execCommand('print', false, null);
                } else {
                    iframe.contentWindow.focus();
                    iframe.contentWindow.print();
                }
            });
        }
    };
});
like image 40
Travis Avatar answered Nov 15 '22 17:11

Travis