Ext JS 4/Ext JS 6: Printing the contents of an Ext.Panel

If you’re creating a line-of-business application, chances are pretty good that your users will need to print some data generated by your application.

printpanel

As illustrated by the following code snippet, printing the contents of an Ext 4 panel is relatively straightforward. The basic algorithm is as follows:

  1. Instantiate a hidden iframe
  2. Dynamically copy the CSS of your app into the iFrame
  3. Dynamically copy the contents of the panel into the iFrame
  4. Call the window.print() method on the iFrame
  5. Destroy the iFrame
Ext.define('MyApp.view.override.Panel', {
    override: 'Ext.panel.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();

    }
});

Once you’ve loaded the override, you can simply call the panel.print() method.

Happy coding!

*********************
* UPDATED FOR EXTJS 6
*********************

Ext.define('MyApp.view.override.Panel', {
    override: 'Ext.panel.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().down('.x-autocontainer-innerCt').dom.innerHTML;
       
        while (markup.indexOf('overflow: auto;') >= 0) {
            markup = markup.replace('overflow: auto;', '');
        }

        var str = Ext.String.format('<html><head>{0}</head><body><img src="resources/images/gabar-logo.gif">{1}</body></html>', '', 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();

    }
});

22 thoughts on “Ext JS 4/Ext JS 6: Printing the contents of an Ext.Panel

  1. Razgriz

    Sorry for double posting but I’ve encountered the “Print Preview Failed” message whenever I have a Grid Panel or a Property Panel in my form.

    Reply
  2. Albert

    Hi mate,
    My name is Albert and I don’t write English very well.
    Thanks for providing this implementation.
    My problem is that I tried to print a GMapPanel but markers (icons) are not shown. Could you help me? Thank you very much!

    Reply
    1. sdrucker Post author

      I’ve never tried to print the contents of a GMapPanel, but presumably the icons aren’t printing because they’re implemented as a background-image. With Chrome and Safari you can add the CSS style “-webkit-print-color-adjust: exact;” to the element to force print the background color and/or image. There’s a couple of other hacks mentioned here:
      http://stackoverflow.com/questions/6670151/how-can-i-force-browsers-to-print-background-images-in-css

      Reply
      1. Albert

        Thanks for your quick response.
        Who do I have to add this style? At GMapPanel? I’m a little lost 🙂

  3. Razgriz

    Can we have a callback on the print command to make sure if the user did click “Print” in print dialogue or just cancelled it?

    Reply
  4. Pingback: ExtJS 4 – creating a callback for an override function for printing panel contents | 我爱源码网

  5. Razgriz

    Another question, it seems that it does not print checkboxes and radio buttons, have you had a workaround for this?

    Reply
  6. Marcel

    In ExtJS6 the CSS from the Ext theme isn’t applied to the printed document. Is there something I’m missing? Or should I supply the css in a seperate css file?

    Reply
  7. sdrucker Post author

    That’s a feature, not s bug. This solution was designed to only output the text content from a panel, and not the Ext widgets. Therefore, you don’t need all of the overhead of the Ext styles.

    Reply
  8. Marcel

    Thanks for the reply and solution. So if I need formatting on the output I should supply css to the output. This just gives the plain text output (Font seems the system font on printing, something like Times New Roman).

    Reply
  9. Rekha

    Hi,
    I am trying to get the Print Preview of my Grid Panel, It prints out all contents but the Column header values are messed up. can you please help me to display the Header of all the columns on that. I tried your code as above. Do I need to add anything as part of the stylesheets?

    Reply

Leave a comment