2

The problem is that the new content will not print (a few more elements).

When the user clicks my print link then I add more html to the document before window.print() is called.

I use ajax to fetch more chapters for a book before printing.

Code:

Print initialized:

var afterPrint = function () {

  var timer = setInterval(function () {

    afterContentPrint(); // Cleanup html (restore to initial state)
    clearInterval(timer);

  }, 900);
}
//window.onbeforeprint = beforePrint;
window.onafterprint = afterPrint;

Event print click:

$("#print-test").click(function (e) {

   e.preventDefault();

   beforeContentPrint(); // ajax call for additional content, finishing by calling window.print()
});

In function beforeContentPrint():

var jqxhr = $.ajax({

   type: "GET",
   url: bookURL,

   success: function(data) {
     .....
     .....

     $(article).each(function () {
        parent.append(article);

     });
   },
   complete: function() {
     var timer = setInterval(function () {
        window.print();
     }, 900);
  }
 }

The new content is visibly added to the HTML document, so it should work. But only the initial content (before ajax call) is picked up for print.

This solution is for IE and Firefox (onbeforeprint and onafterprint).

Using window.matchMedia('print') seems to work fine in Chrome with this logic.

gorn
  • 8,097
  • 5
  • 37
  • 44

4 Answers4

1

I don't know why this is happening but there is a working around in mozilla docs; printing a hidden iframe, then you open more chapters of the book with no need to shows up. Here the link https://developer.mozilla.org/en-US/docs/Printing

Here the code:

<!doctype html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>MDN Example</title>
<script type="text/javascript">
function closePrint () {
  document.body.removeChild(this.__container__);
}

function setPrint () {
  this.contentWindow.__container__ = this;
  this.contentWindow.onbeforeunload = closePrint;
  this.contentWindow.onafterprint = closePrint;
  this.contentWindow.print();
}

function printPage (sURL) {
  var oHiddFrame = document.createElement("iframe");
  oHiddFrame.onload = setPrint;
  oHiddFrame.style.visibility = "hidden";
  oHiddFrame.style.position = "fixed";
  oHiddFrame.style.right = "0";
  oHiddFrame.style.bottom = "0";
  oHiddFrame.src = sURL;
  document.body.appendChild(oHiddFrame);
}
</script>
</head>

<body>
  <p><span onclick="printPage('externalPage.html');" style="cursor:pointer;text-decoration:underline;color:#0000ff;">Print external page!</span></p>
</body>
</html>
Scoup
  • 1,323
  • 8
  • 11
1

1st Attempt : try putting asyn:false in the ajax request of beforeContentPrint, so that the elements will be added first then the print will be called.

var jqxhr = $.ajax({

   type: "GET",
   url: bookURL,
   async:false,
   success: function(data) {
     .....
     .....

     $(article).each(function () {
        parent.append(article);

     });
   },
   complete: function() {
     var timer = setInterval(function () {
        window.print();
     }, 900);
  }
 }

2ndAttempt: Take a look Here how to force execution of one function after another. Hope this helps.

Community
  • 1
  • 1
sudhansu63
  • 6,025
  • 4
  • 39
  • 52
  • OP has window.print on complete callback which definitely being called after success... clearly async isn't an issue – j03w Sep 06 '13 at 15:48
0

It looks like the setInterval, clearInterval is what is messing you up. Change to a setTimeout and get rid of the clearInterval in your afterprint function. I made a fiddle that works in FF and IE9. Fiddle

    complete: function() {
        var timer = setTimeout(function () {
        window.print();
      }, 900);
    }
Tim Mickey
  • 361
  • 3
  • 10
  • I did use `setTimeout` with a few seconds before calling print, and it did not work. I tried also to separate the two processes by using `success: function(data) {}` for ajax and `complete: function() {}` for `window.print`, which didn't solve it either. Hmmm. – gorn Sep 02 '13 at 09:41
0

As the elements added aren't shown it can be a little hard to pinpoint the exact problem, but adding elements via appending/inserting into document doesn't always work that well for all browsers and in worst case you will need to add those elements manually by code (document.createElement(), appendChild() etc.).

In an attempt to create a work-around you can try to use MutationObservers to track changes for your article element which can hopefully help you trigger print when DOM is updated properly. The support is fairly good in new browsers (you may have to use prefix in some, f.ex. WebKitMutationObserver) and for older browsers you can provide a fallback - which of course then only get you so far.

This will monitor a target element for changes and fire a callback.

Generic example based on this article:

var article = document.querySelector('#articleID'),
    doPrint = false,    // must be available in global/parent scope
    o,
    useFallback = (typeof MutationObserver !== 'undefined');


if (!useFallback) {    
    o = new MutationObserver(function(mutations) {
        mutations.forEach(function(mutation) {

           // you can do additional filtering here
           // using the mutation object (.name, .type, ...)

           if (doPrint) {
               doPrint = false;
               window.print();
           }
       });
    });

    var cfg = { attributes: true, childList: true, characterData: true };

    o.observe(article, cfg);
}

Now that the observer is running you can do this modification in your success callback:

var timer;  // keep track of setTimeout so we can cancel it

success: function(data) {
   ...
   ...

$(article).each(function () {

    parent.append(article);

  });

  // after last element is added, add a "dummy" element
  doPrint = true;

  if (useFallback) {
     // fallback to setTimeout or other solution
  }
  else {
     parent.append('<br />');
  }

}

I made an online demo here which sets up the observer and adds some elements. Open console to see actions. The demo is probably too limited data-wise to simulate your situation but can be useful to see the process.

The mechanism used here for triggering print dialog itself can be discussed if is the best - I just provide one for sake of example.

But you can see the observer is triggered when something is added to article. This way you know the DOM has been updated and it should be available for printing. Only the last element added need to trigger the print, hence the doPrint flag.

If you still have no success you will need to consider adding the elements manually the code way or perhaps predefine some elements that you inject when needed (as said, without knowing the full scenario here it has to be with the guess).