34

I have a single page web application using angularJS. I need to print a div of certain page. I tried the following:

The page contains few div (print.html)

<div>
  <div>
    Do not print
  </div>
  <div id="printable">
    Print this div
  </div>
  <button ng-click="printDiv('printableArea');">Print Div</button>
</div>

The controller has following script:

$scope.printDiv = function(divName) {
    var printContents = document.getElementById(divName).innerHTML;
    var originalContents = document.body.innerHTML;        
    document.body.innerHTML = printContents;
    window.print();
    document.body.innerHTML = originalContents;
}

This code prints the desired div but there is a problem. the statement document.body.innerHTML = originalContents; replaces the body of the whole application since it is a SPA. So when I refresh the page or click on print button again, the whole content of the page is erased.

Cœur
  • 37,241
  • 25
  • 195
  • 267
Priyatam Roy
  • 431
  • 1
  • 5
  • 11

7 Answers7

90
$scope.printDiv = function(divName) {
  var printContents = document.getElementById(divName).innerHTML;
  var popupWin = window.open('', '_blank', 'width=300,height=300');
  popupWin.document.open();
  popupWin.document.write('<html><head><link rel="stylesheet" type="text/css" href="style.css" /></head><body onload="window.print()">' + printContents + '</body></html>');
  popupWin.document.close();
} 
alexkb
  • 3,216
  • 2
  • 30
  • 30
Anand Natarajan
  • 1,172
  • 8
  • 7
  • All `$http` requests brakes after this... :( Also I can't to reload page... only copy url to new tab works... I can't to understand why.. – vp_arth May 27 '14 at 10:17
  • The same here, all $http request brakes but only happen with Chrome when I close the new window. Firefox or IE works well – Eduardo Chavira Jun 19 '14 at 14:47
  • 1
    I found why is not working this solution, here is the answer - http://stackoverflow.com/questions/23071291/javascript-window-print-in-chrome-closing-new-window-or-tab-instead-of-cancel – Eduardo Chavira Jun 19 '14 at 15:33
  • Why does he get var originalContents = document.body.innerHTML; he doesn't use originalContents anywhere – AlexandruC Nov 27 '14 at 11:33
  • Is there any function like this for specific div convert and download as pdf file? – gsk Apr 04 '15 at 13:55
  • This works great for me except it leaves a window open containing the document after I click "Print" or "Cancel" in the print dialog. Is it possible to close that window after printing or canceling? – John Mark Dec 15 '15 at 19:35
  • Popup not closed after print. – Chinmay235 Apr 25 '17 at 05:45
  • The above solution worked, however the styles like font color and div background colors are not being printed as on screen! any suggestions? – HARDIK THAKOR Jul 10 '17 at 08:21
11

Two conditional functions are needed: one for Google Chrome, and a second for the remaining browsers.

$scope.printDiv = function (divName) {

    var printContents = document.getElementById(divName).innerHTML; 

    if (navigator.userAgent.toLowerCase().indexOf('chrome') > -1) {
        var popupWin = window.open('', '_blank', 'width=600,height=600,scrollbars=no,menubar=no,toolbar=no,location=no,status=no,titlebar=no');
        popupWin.window.focus();
        popupWin.document.write('<!DOCTYPE html><html><head>' +
            '<link rel="stylesheet" type="text/css" href="style.css" />' +
            '</head><body onload="window.print()"><div class="reward-body">' + printContents + '</div></body></html>');
        popupWin.onbeforeunload = function (event) {
            popupWin.close();
            return '.\n';
        };
        popupWin.onabort = function (event) {
            popupWin.document.close();
            popupWin.close();
        }
    } else {
        var popupWin = window.open('', '_blank', 'width=800,height=600');
        popupWin.document.open();
        popupWin.document.write('<html><head><link rel="stylesheet" type="text/css" href="style.css" /></head><body onload="window.print()">' + printContents + '</body></html>');
        popupWin.document.close();
    }
    popupWin.document.close();

    return true;
}
Ariel
  • 911
  • 1
  • 15
  • 40
Jadli
  • 858
  • 1
  • 9
  • 17
7

You can now use the library called angular-print

TMichel
  • 4,336
  • 9
  • 44
  • 67
  • 1
    This library is in flux, I'd be careful about using it in production until some of the issues get resolved – G.Mart Dec 10 '15 at 20:00
  • @G.Mart Apparently the author is pushing a [major release](https://github.com/samwiseduzer/angularPrint/issues/7#issuecomment-163067195) this weekend solving the cross-browser compatibility – TMichel Dec 11 '15 at 08:29
  • 2
    From the author, 3 days ago: "Yeah, I'm really sorry for the lack of updates on multi-browser compatibility. I anticipate releasing a new version this weekend that supports chrome, mozilla and safari. Edge will be mostly supported, but may still have a bug or two.chrome, mozilla and safari. Edge will be mostly supported, but may still have a bug or two." – G.Mart Dec 11 '15 at 16:35
  • So unfortunately no reference of IE, and edge will be a tossup. – G.Mart Dec 11 '15 at 16:35
1

I done this way:

$scope.printDiv = function (div) {
  var docHead = document.head.outerHTML;
  var printContents = document.getElementById(div).outerHTML;
  var winAttr = "location=yes, statusbar=no, menubar=no, titlebar=no, toolbar=no,dependent=no, width=865, height=600, resizable=yes, screenX=200, screenY=200, personalbar=no, scrollbars=yes";

  var newWin = window.open("", "_blank", winAttr);
  var writeDoc = newWin.document;
  writeDoc.open();
  writeDoc.write('<!doctype html><html>' + docHead + '<body onLoad="window.print()">' + printContents + '</body></html>');
  writeDoc.close();
  newWin.focus();
}
Azhar
  • 693
  • 9
  • 22
0

This is what worked for me in Chrome and Firefox! This will open the little print window and close it automatically once you've clicked print.

var printContents = document.getElementById('div-id-selector').innerHTML;
            var popupWin = window.open('', '_blank', 'width=800,height=800,scrollbars=no,menubar=no,toolbar=no,location=no,status=no,titlebar=no,top=50');
            popupWin.window.focus();
            popupWin.document.open();
            popupWin.document.write('<!DOCTYPE html><html><head><title>TITLE OF THE PRINT OUT</title>' 
                                    +'<link rel="stylesheet" type="text/css" href="app/directory/file.css" />' 
                                    +'</head><body onload="window.print(); window.close();"><div>' 
                                    + printContents + '</div></html>');
            popupWin.document.close();
Azhar
  • 693
  • 9
  • 22
tyborg
  • 553
  • 4
  • 8
0

Okay i might have some even different approach.

I am aware that it won't suit everybody but nontheless someone might find it useful.

For those who do not want to pupup a new window, and like me, are concerned about css styles this is what i came up with:

I wrapped view of my app into additional container, which is being hidden when printing and there is additional container for what needs to be printed which is shown when is printing.

Below working example:

var app = angular.module('myApp', []);
 app.controller('myCtrl', function($scope) {
  
    $scope.people = [{
      "id" : "000",
      "name" : "alfred"
    },
    {
      "id" : "020",
      "name" : "robert"
    },
    {
      "id" : "200",
      "name" : "me"
    }];

    $scope.isPrinting = false;
  $scope.printElement = {};
  
  $scope.printDiv = function(e)
  {
   console.log(e);
   $scope.printElement = e;
   
   $scope.isPrinting = true;
      
      //does not seem to work without toimeouts
   setTimeout(function(){
    window.print();
   },50);
   
   setTimeout(function(){
    $scope.isPrinting = false;
   },50);
   
   
  };
    
  });
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>

<div ng-app="myApp" ng-controller="myCtrl">

 <div ng-show="isPrinting">
  <p>Print me id: {{printElement.id}}</p>
    <p>Print me name: {{printElement.name}}</p>
 </div>
 
 <div ng-hide="isPrinting">
    <!-- your actual application code -->
    <div ng-repeat="person in people">
      <div ng-click="printDiv(person)">Print {{person.name}}</div>
    </div>
  </div>
  
  
</div>
 

Note that i am aware that this is not an elegant solution, and it has several drawbacks, but it has some ups as well:

  • does not need a popup window
  • keeps the css intact
  • does not store your whole page into a var (for whatever reason you don't want to do it)

Well, whoever you are reading this, have a nice day and keep coding :)

EDIT:

If it suits your situation you can actually use:

@media print  { .noprint  { display: none; } }
@media screen { .noscreen { visibility: hidden; position: absolute; } }

instead of angular booleans to select your printing and non printing content

EDIT:

Changed the screen css because it appears that display:none breaks printiing when printing first time after a page load/refresh.

visibility:hidden approach seem to be working so far.

-3

I don't think there's any need of writing this much big codes.

I've just installed angular-print bower package and all is set to go.

Just inject it in module and you're all set to go Use pre-built print directives & fun is that you can also hide some div if you don't want to print

http://angular-js.in/angularprint/

Mine is working awesome .

  • This does not provide an answer to the question. Once you have sufficient [reputation](https://stackoverflow.com/help/whats-reputation) you will be able to [comment on any post](https://stackoverflow.com/help/privileges/comment); instead, provide answers that [don't require clarification from the asker](https://meta.stackexchange.com/questions/214173/why-do-i-need-50-reputation-to-comment-what-can-i-do-instead). – GrumpyCrouton Jun 30 '17 at 13:15
  • Thanks for the advice, but I think answer is much accurate. And it works 100%. – Palak Dhingra Jul 03 '17 at 13:14
  • There is also already an answer that is basically the same as yours, so yours doesn't add anything new to this thread. I would say even that other answer is invalid though as it is _only a link to an external source_ which could be off topic, and if that link breaks your answer and their answer are both broken because your answer IS the link. – GrumpyCrouton Jul 03 '17 at 14:26
  • this is very foolish –  Aug 27 '18 at 18:10