Search code examples
javascriptformsextjsextjs4extjs4.2

ExtJS 4 - Printing Forms Programatically sometimes gives "Print Preview Failed" in Chrome


Good day. I am developing a Web Application and there's a part where I print the form on button click. To achieve this, I overrode the definition of my Form Panel so that I can call form.print() anywhere in my code when I need to. Here is how I overrode my form:

Ext.define('my_app_name.override.form.Panel', {
    override: 'Ext.form.Panel', 

    print: function(pnl) {
        if (!pnl) {
            pnl = this;
        }

        // instantiate hidden iframe
        var iFrameId = "printerFrame";
        var printFrame = Ext.get(iFrameId);

        if (printFrame === null) {
            printFrame = Ext.getBody().appendChild({
                id: iFrameId,
                tag: 'iframe',
                cls: 'x-hidden',
                style: {
                    display: "none"
                }
            });
        }

        var cw = printFrame.dom.contentWindow;

        // instantiate application stylesheets in the hidden iframe
        var stylesheets = "";
        for (var i = 0; i < document.styleSheets.length; i++) {
            stylesheets += Ext.String.format('<link rel="stylesheet" href="{0}" />', document.styleSheets[i].href);
        }

        // various style overrides
        stylesheets += ''.concat(
            "<style>", 
            ".x-panel-body {overflow: visible !important;}",
            // experimental - page break after embedded panels
            // .x-panel {page-break-after: always; margin-top: 10px}",
            "</style>"
        );

        // get the contents of the panel and remove hardcoded overflow properties
        var markup = pnl.getEl().dom.innerHTML;
        while (markup.indexOf('overflow: auto;') >= 0) {
            markup = markup.replace('overflow: auto;', '');
        }

        var str = Ext.String.format('<html><head>{0}</head><body>{1}</body></html>',stylesheets,markup);

        // output to the iframe
        cw.document.open();
        cw.document.write(str);
        cw.document.close();

        // remove style attrib that has hardcoded height property
        cw.document.getElementsByTagName('DIV')[0].removeAttribute('style');

        // print the iframe
        cw.print();

        // destroy the iframe
        Ext.fly(iFrameId).destroy();
    }
});

Then on a click of a button in my Web App, I do something like:

var form = Ext.getCmp('formIDHere');
form.print();

However, this code is rather inconsistent at times. There are times that I can print the form no problem and there are times that it gives the "Print Preview Error" message. I can't replicate the issue consistently and the logs aren't showing anything so I'm in the dark.

What I've noticed however, is that when I save my project (I'm using Sencha Architect), preview it (or refresh the current window where I'm previewing my Web App), stay with the web app all throughout the process (meaning I don't shift tabs or windows), hit the print button, the print preview appears and I don't have problems with it.

So far I haven't tested in other Web Browsers. Any ideas anyone? I'll be really thankful for anyone who can point out what I'm doing wrong. Thanks in advance.


Solution

  • Sorry I forgot to update this. Thanks to whoever upvoted my question.

    The concept is simple. Since ExtJS4 is asynchronous, I placed my code in "blocks" and then I delayed my calls to those functions to ensure that they finish constructing what they need to construct before moving on to the next part.

    print: function(pnl) {
    
        if (!pnl) {
            pnl = this;
        }
    
        // instantiate hidden iframe
    
        var iFrameId = "printerFrame";
        var printFrame = Ext.get(iFrameId);
    
        if (printFrame === null) {
            printFrame = Ext.getBody().appendChild({
                id: iFrameId,
                tag: 'iframe',
                cls: 'x-hidden',
                style: {
                    display: "none"
                }
            });
        }
    
        var cw = printFrame.dom.contentWindow;
        var stylesheets = "";
        var markup;
        // instantiate application stylesheets in the hidden iframe
    
    
    
        var printTask = new Ext.util.DelayedTask(function(){
            // print the iframe
            cw.print();
    
            // destroy the iframe
            Ext.fly(iFrameId).destroy();
    
        });
    
    
        var strTask = new Ext.util.DelayedTask(function(){
            var str = Ext.String.format('<html><head>{0}</head><body>{1}</body></html>',stylesheets,markup);
    
    
            // output to the iframe
            cw.document.open();
            cw.document.write(str);
            cw.document.close();
    
            // remove style attrib that has hardcoded height property
            //             cw.document.getElementsByTagName('DIV')[0].removeAttribute('style');
            printTask.delay(500);
    
        });
    
        var markUpTask = new Ext.util.DelayedTask(function(){
            // get the contents of the panel and remove hardcoded overflow properties
            markup = pnl.getEl().dom.innerHTML;
            while (markup.indexOf('overflow: auto;') >= 0) {
                markup = markup.replace('overflow: auto;', '');
            }
            while (markup.indexOf('background: rgb(255, 192, 203) !important;') >= 0) {
                markup = markup.replace('background: rgb(255, 192, 203) !important;', 'background: pink !important;');
            }
    
            strTask.delay(500);
        });
    
    
        var styleSheetConcatTask = new Ext.util.DelayedTask(function(){
    
            // various style overrides
            stylesheets += ''.concat(
                "<style>", 
                ".x-panel-body {overflow: visible !important;}",
                // experimental - page break after embedded panels
                // .x-panel {page-break-after: always; margin-top: 10px}",
                "</style>"
            );
    
            markUpTask.delay(500);
        });
    
    
        var styleSheetCreateTask = new Ext.util.DelayedTask(function(){
    
    
            for (var i = 0; i < document.styleSheets.length; i++) {
                stylesheets += Ext.String.format('<link rel="stylesheet" href="{0}" />', document.styleSheets[i].href);
            }
            styleSheetConcatTask.delay(500);
        });
    
        styleSheetCreateTask.delay(500);
    }