Problems with jQuery print function

1

Galera I put a code in jQuery to make some changes to my layout by hiding some div and printing the page. It works fine, however I'm having the following problem.

When I have an image on my page, the system prints before loading images. How do I get it to print only after full page loading.

Follow my code:

    <script>

    // Imprime a página
    window.print();

    $(document).ready(function () {
        var beforePrint = function () {

            // Remove o loading
            $(".se-pre-con").hide();

            // Remove Menu topo
            $(".header").hide();
            $('body').css({"padding-top": "0px"});
        };
        var afterPrint = function () {
            // Redireciona página
            window.location = 'www.google.com.br';
        };

        if (window.matchMedia) {
            var mediaQueryList = window.matchMedia('print');
            mediaQueryList.addListener(function (mql) {
                if (mql.matches) {
                    beforePrint();
                } else {
                    afterPrint();
                }
            });
        }

        window.onbeforeprint = beforePrint;
        window.onafterprint = afterPrint;
    }());
</script>

asked by anonymous 13.09.2016 / 22:33

2 answers

2

Just stop calling the function you declared in the first parameter of $.fn.ready . And now you could call this.print in the block of that function.

In jQuery, this "ready" event happens when each element of a jQuery list has its% property of% assigned with readyState (I believe) - this event next to "complete" would be like waiting for all content of the page being loaded and interpreted by the browser.

Remembering, there is also the document method to set events in jQuery, if you prefer.

You can also call jQuery itself to set this event only with $.fn.on(event, callback) : document , more information .

Edit : Until the jQuery "ready" event runs, your images will load, but you will not know if they will be rendered at the same time. To execute $(callback) you can make a delay with the help of print or requestAnimationFrame . setTimeout would be ideal since it runs while the page is active.

I just created a interface using requestAnimationFrame or requestAnimationFrame to create a delay with count event. You can force it to not use setTimeout . When requestAnimationFrame is not supported the interface uses requestAnimationFrame to run a delay.

So here's an example of using this interface:

/*! Delayer.js */
;(function(a){"use strict";function c(a,c){var d=a[c];if(!d&&(c=c.charAt(0).toUpperCase()+c.substring(1)))for(var e=0,f=b.length;e<f&&!(d=a[b[e]+c]);++e);return d}function j(a,b){for(var c=0,d=a.events[b].length;c<d;++c){var e=a.events[b][c];e.call(e.target)}}function k(a){a.tId=d(function(){k(a)}),(a._elapsed=(a._now=f())-a._then)>a.wait&&(a._then=a._now-a._elapsed%a.wait,j(a,"count"))}function l(a){a.tId=setTimeout(function(){a.isRunning&&(j(a,"count"),l(a))},a.wait)}function m(a){for(var b,c=0,d=h.length;c<d;++c)if(h[c].identifier===a){b=h[i=c];break}return b}function n(){var b,a=h.length-1;if(a<0)b=0;else if(0===a){for(var c=0,d=h[0].identifier;c===d;++c);b=c}else for(var c=0;c<=a;++c)if(c>=a)b=c+1;else if((b=h[c].identifier+1)<h[c+1].identifier)break;this.identifier=b,g(this),h.push({delay:18,events:{count:[]},forceRAF:!0,identifier:b})}var i,b=["webkit","moz","ms"],d=c(a,"requestAnimationFrame"),e=c(a,"cancelAnimationFrame")||c(a,"cancelRequestAnimationFrame"),f="object"==typeof a.performance&&performance.now?function(){return performance.now()}:function(){return(new Date).getTime()},g="function"==typeof Object.defineProperty?function(a){var b=a.identifier;Object.defineProperty(a,"identifier",{value:b,writable:!1})}:Function.prototype,h=[];n.prototype={animation:function(a){var b=m(this.identifier);return"boolean"==typeof a&&(b.forceRAF=a,b.isRunning&&(b.stop(),b.start())),this},count:function(a){return"function"==typeof a&&this.on("count",a),this},delay:function(a){var b=m(this.identifier);return"number"==typeof a?(b.wait=a,b.isRunning&&(b.stop(),b.start()),this):b.wait},dismantle:function(){return this.stop(),h.splice(i,1),h.sort(function(a,b){return a.identifier-b.identifier}),!0},on:function(a,b){if(b.target=this,"function"==typeof b){for(var c=m(this.identifier),d=a.split(" "),e=0,f=d.length;e<f;++e){var g;typeof(!(g=c.events[d[e]])instanceof Array)&&(g=c.events[d[e]]=[]),g.push(b)}return this}},start:function(){var a=m(this.identifier);return a.isRunning=!0,(a.isUsingRAF=a.forceRAF&&"function"==typeof d)?(a._then=f(),k(a)):l(a),this},stop:function(){var a=m(this.identifier);return a.isRunning&&((a.isUsingRAF?e:clearTimeout)(a.tId),a.isRunning=!1),this}};var o=function(){return new n};"object"==typeof a.module&&module.exports?module.exports=exports=o:a.Delayer=o})(this);

var root = this

$(document).ready(function () {

    Delayer()

        .count(function() {
            /* Desmonta o atrasador. */
            this.dismantle()
            /* Imprime a página. */
            root.print()
        }

        .delay(500) // Esperaremos 500ms.
})

In jQuery do something a little similar to this to run the setTimeout event of each element in a list (based on some SOen posts),

;(function() {

    var isDocLoaded

    (isDocLoaded = function() {
        document['readyState'] === "complete" && callback()
    })()

    document['onreadystatechange'] = isDocLoaded

})();

In fact not every element has the $.fn.ready property. Some have, such as readyState , HTMLAudioElement , etc, but HTMLVideoElement / Image has events like "load" that may end up not happening if the event is set after the requested feature loads.     

14.09.2016 / 01:45
0

I'll suggest another approach to this problem, which involves using the load event. Although the ready event ensures that the entire DOM structure is already built, it does not guarantee that all assets (images, CSS, and so on) have already been fully loaded. You can do

$(document).on('load', function()){
    window.print();
}

to ensure that the print instruction is only fired when the images are already loaded. This answer from gringo OS talks about difference of 2 events.

As for hiding some things in the print version (which I believe is what the rest of your method does), just create a media query (in your .css file, if it exists) to print , as follows:

@media print{
    .se-pre-con, header{
        display: none;
    }
    body{
        padding-top: 0;
    }
}
    
20.09.2016 / 15:33