Problems with jQuery printing function

Asked

Viewed 317 times

1

Guys I put together a code in jQuery to make some changes to my layout by hiding some div and printing the page. It works very well, but I’m having the following problem.

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

Follows 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';
        };

        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>

_______________________________ I’m trying like this ______________________

    <script>

    var root = this;

    $(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 = 'google.com';
        };

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

        window.onbeforeprint = beforePrint;
        window.onafterprint = afterPrint;

        /* Imprime a página */
        root['print']();
    });

</script>

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 that function block.

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

Remember, there is also the method $.fn.on(event, callback) to set events in jQuery, if you prefer.

It is also possible to call jQuery himself to define this event only with the document: $(callback), more information.

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

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

So here’s an example with the use of 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 event $.fn.ready of each element in a list (based on some Soen posts),

;(function() {

    var isDocLoaded

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

    document['onreadystatechange'] = isDocLoaded

})();

Actually not every element has property readyState. Some have, like the HTMLAudioElement, HTMLVideoElement, etc, but Image/HTMLImageElement has events like "load" that may end up not happening if the event is set after the requested resource loads.

  • Well I tried to do the way you explained here, and it’s not working, could you give me an example with my code? I broke my head here and not right, it prints but still does not load the images

  • I’m not loading it into html anyway. I’ll edit my question so you can see I’m trying ok

  • Look I switched the root['print'](); for setTimeout(root.print, 1); the only problem is that it takes 1 second to send the print command.

  • good the requestAnimationFrame(root.print) didn’t work, just doesn’t print. well I guess the setTimeout(root.print, 300) is not functional for those who have slow internet, imagine if it goes past 300ms and the image has not yet uploaded. Will give problem right.

  • I updated the answer. And, no, this does not depend on the internet, the images will already have loaded before the callback of the "ready" event run.

0

I will suggest another approach to this problem, which involves the use of the event load. Despite the event ready ensure that the whole structure of the DOM 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 of the SO gringo talks about the difference of the 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 impression, as follows:

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

Browser other questions tagged

You are not signed in. Login or sign up in order to post.