Print a div using javascript in angularJS single page application
Asked Answered
G

7

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.

Grevera answered 5/3, 2014 at 5:42 Comment(1)
Please include a fiddle.Moldau
G
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();
} 
Goldofpleasure answered 5/3, 2014 at 5:49 Comment(8)
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..Bacteriology
The same here, all $http request brakes but only happen with Chrome when I close the new window. Firefox or IE works wellZygoma
I found why is not working this solution, here is the answer - #23071791Zygoma
Why does he get var originalContents = document.body.innerHTML; he doesn't use originalContents anywhereBumpy
Is there any function like this for specific div convert and download as pdf file?Oof
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?Commanding
Popup not closed after print.Karalee
The above solution worked, however the styles like font color and div background colors are not being printed as on screen! any suggestions?Gettysburg
K
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;
}
Kammerer answered 9/7, 2014 at 20:51 Comment(2)
Why do you have onbeforeunload and originalContents? Also, you are missing the </body> tags from the popupWin.document.write lines.Homograft
Very nice thank you, just a unused variable: originalContentsHartzel
Q
7

You can now use the library called angular-print

Quirita answered 4/9, 2015 at 7:23 Comment(4)
This library is in flux, I'd be careful about using it in production until some of the issues get resolvedThrenody
@Threnody Apparently the author is pushing a major release this weekend solving the cross-browser compatibilityQuirita
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."Threnody
So unfortunately no reference of IE, and edge will be a tossup.Threnody
A
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();
}
Arrack answered 2/8, 2016 at 6:50 Comment(0)
J
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();
Joycejoycelin answered 28/6, 2016 at 19:38 Comment(0)
D
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.

Deepfreeze answered 13/10, 2018 at 14:0 Comment(0)
W
-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 .

Whitening answered 30/6, 2017 at 12:43 Comment(4)
This does not provide an answer to the question. Once you have sufficient reputation you will be able to comment on any post; instead, provide answers that don't require clarification from the asker.Neisa
Thanks for the advice, but I think answer is much accurate. And it works 100%.Whitening
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.Neisa
this is very foolishAgnola

© 2022 - 2024 — McMap. All rights reserved.