Ext.ux.Printer – printing for any ExtJS Component

After my recent foray into printing grids with ExtJS, I realised I needed to print some trees too. Seeing as some of the work was already done for the Grid example, it made sense to create a common API for printing any Ext.Component. And thus Ext.ux.Printer was born:

var grid = new Ext.grid.GridPanel({ // just a normal grid });
var tree = new Ext.tree.ColumnTree({ // just a normal column tree });

Ext.ux.Printer.print(grid);
Ext.ux.Printer.print(tree);

Each of the above opens a new window, renders some HTML (just a big table really), prints it and closes the window – all client side with no server side code required. Although trees and grids represent data quite differently internally, we can use the same API on Ext.ux.Printer to print them both.

Ext.ux.Printer uses Renderer classes to cope with a specific xtype, and adding Renderers for other components is easy. At the moment Ext.grid.GridPanel and Ext.tree.ColumnTree are supported out of the box, but let’s see how we’d add support for printing the contents of an Ext.Panel:

/**
 * Prints the contents of an Ext.Panel
 */
Ext.ux.Printer.PanelRenderer = Ext.extend(Ext.ux.Printer.BaseRenderer, {

 /**
  * Generates the HTML fragment that will be rendered inside the <html> element of the printing window
  */
 generateBody: function(panel) {
   return String.format("<div class='x-panel-print'>{0}</div>", panel.body.dom.innerHTML);
 }
});

Ext.ux.Printer.registerRenderer("panel", Ext.ux.Printer.PanelRenderer);

This is probably the simplest print renderer of all – we’re simply grabbing the HTML from inside a the panel’s body and returning it inside our own div. We subclassed Ext.ux.Printer.BaseRenderer, and in this case all we needed to do was provide an implementation for generateBody. Whatever this function returns is rendered inside the <body> tag of the newly-opened printing window.

Notice that we registered this renderer for all components with the xtype of ‘panel’. Internally, Ext.ux.Printer examines the xtype chain of the component you pass it to print, and uses the first renderer that matches. As many Ext components inherit from Ext.Panel this can function as a catch-all renderer.

Here’s how we’d use our new renderer:

var panel = new Ext.Panel({
  html: {
    tag: 'ul',
    chidren: [
      {tag: 'li', text: 'Item 1'},
      {tag: 'li', text: 'Item 2'},
      {tag: 'li', text: 'Item 3'}
    ]
  }
});

Ext.ux.Printer.print(panel);

Pretty straightforward. You can now print Ext.Panels the same way you’d print a Grid or a Tree. Take a look at the Grid Renderer and the ColumnTree Renderer for examples of rendering more advanced components.

As usual, all of the Ext.ux.Printer source is available on Github, and the README file there contains instructions for installation and usage.

Finally, when the printing window is opened it includes a stylesheet that it expects to find at “/stylesheets/print.css”. There is a default print.css stylesheet included with the extension to get you started, and you can specify where to find this stylesheet like this:

Ext.ux.Printer.BaseRenderer.prototype.stylesheetPath = '/path/to/print/stylesheet.css';

51 Responses to Ext.ux.Printer – printing for any ExtJS Component

  1. weazil says:

    Awesome addon, found it easy to implement and use was just curious about grid striping rows I've toyed with it with minimal success

  2. Anonymous says:

    God job, thank you for sharing. But this component not work on ie8 ( May be run ie7, ie6 …). I change the code "print" method on "Base.js" from "String.format("print-{0}-{1}…" to "String.format("print_{0}_{1}…" and it is working now.Thanks againEbabil

  3. Edward Spencer says:

    Hi Ebabil, Thanks for the heads up – I've pushed your fix up onto Github now. There's also a Printer-all.js file there now, which includes all the files in the right order for you.Ed

  4. weazil says:

    toying some more with the print addonif i render a field with a qtip it seems to break it{ header: "Job", dataIndex: 'job_id', sortable: true, renderer: function(val,cell,record){ if(val != '') cell.attr = 'ext:qtip="'+record.data.tooltip+'" ext:qchilds="true"'; return val; } }if i remove the cell.attr it works fine also I modified the grid generateBody functionFROM ,headings,body TO '<thead>'+headings+'</thead>', bodythat way at the top of every page it has the grid headerMaybe i'm placing the qtip on there incorrect I'm no ext expert by far.

  5. TopKatz says:

    Ed, this is brilliant!!!

  6. TopKatz says:

    I made a modification to allow for setting the title. I have some panels that the title is non-descriptive, however I needed the printed version to be a little more verbose, just replace the getTitle function with this one, and add this property.

    /**
    * Returns the title to give to the print window
    * @param {Ext.Component} component The component to be printed
    * @return {String} The window title
    */
    getTitle: function(component) {
    if(this.manualTitle){
    return this.manualTitle;
    }else{
    return typeof component.getTitle == ‘function’ ? component.getTitle() : (component.title || “Printing”);
    }
    this.manualTitle = null;
    },

    /**
    * @property manualTitle
    * @type String
    * A manualy set titile to override the components
    *
    */

    manualTitle : null,

    Then call it like so:
    Ext.ux.Printer.BaseRenderer.prototype.manualTitle = ‘Some descriptive title!!!’;

  7. TopKatz says:

    BTW: Ed, I can not find a email address to you on the site : (

  8. Jorge says:

    I just started using the component in an internal app. Thank you for sharing.

  9. Paul Holser says:

    Ed, this is a terrific extension! Thanks much!

  10. Pingback: Ext.ux.Exporter – export any Grid to Excel or CSV : Ed Spencer

  11. Itari says:

    Is there an ambition to extend it for Grouping Store???

  12. Great extension!

    Along the lines of Ebabil’s comment, if your component ID has dashes (e.g. my-grid) IE will throw an error on the call to window.open. Here is the quick fix I made:

    String.format(“print_{0}_{1}”, component.getXType(), component.id.replace(/-/g,”_”))

    I also threw in a few ‘n’ characters in the HTML templates to make the output easier to read.

  13. Luca says:

    Hi,

    if i want print ext.window?

  14. Paul says:

    Thank’s you help me a lot

  15. Christiaan says:

    The print popup didn’t work in IE6. I had to add an extra line to Ext.ux.Printer.BaseRenderer (Base.js)

    if(Ext.isIE6) {name=’_blank’;}
    var win = window.open(”, name);

    And also. I tested in a very slow PC with IE6, so the print window appeared after 5 seconds. It may occur that the person closes the popup before the print window opens. In that case you get an error message.
    —————————
    Error
    —————————
    A Runtime Error has occurred.
    Do you wish to Debug?

    Line: 227
    Error: ‘dialogArguments.__IE_PrintType’ is null or not an object
    —————————
    Yes No
    —————————

    Therefore I wrapped win.print and win.close with:

    if (Ext.isIE6 && win.isOpen || !Ext.isIE6 && !win.closed){win.print(); win.close();}

  16. Ivan says:

    Great Component! Thanks! But It doesn’t work in Opera for me. How I can fix it?

  17. Ian says:

    Thanks Ed, that’s a great component.

    It seems to take a long time for the print window to come up when using Firefox (v3.5.8), a lot longer than it does in IE. It works in the end though.

  18. iwosz says:

    I’m using Ext 3.2.1 and newest Ext.ux.Printer, this is from IE8:

    Browser: Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1)
    Message: Invalid argument
    Row: 17
    Char: 5
    Code: 0
    URI: http://localhost/TiMS/bin/js/extjs/plugins/Ext.ux.Printer/renderers/Base.js

    There is some problem with:

    var name = component && component.getXType
    ? String.format(“print_{0}_{1}”, component.getXType(), component.id.replace(/-/g,”_”))
    : “print”;

    var win = window.open(”, name);

  19. Ed Spencer says:

    @iwosz sorry to hear about that. I don’t have a lot of time to give to this thing right now but if you’re able to find a fix and commit it I’d be happy to merge it in.

  20. Gareth says:

    For Row striping i just modified bodyTpl
    It might not be the most elegant solution but it works for me…

    bodyTpl: new Ext.XTemplate(
    ”,
    ”,
    ‘{{dataIndex}}’,
    ”,
    ”,
    {rClassVar: ‘rowClass’, stripeRow: ‘[xindex % 2 === 0 ? “x-grid3-row ” : “x-grid3-row x-grid3-row-alt “]’}
    )

    rowClass is just a value i add to ‘convertedData’ in ‘prepareData’ …it’s just …


    grid.store.data.each(function(item) {
    var convertedData = {};
    convertedData.rowClass = grid.getView().getRowClass(item);

    Thanks a lot Ed this works really well!

  21. Gareth says:

    Hmm i guess all the slashes in the code made my comment go strange…

  22. Gareth says:

    So just put this in the tr of bodyTpl

    class=”{{[this.stripeRow]}} {{[this.rClassVar]}}”‘,

    You just need to escape out one level of the attributes so they get written correctly when the template gets applied.
    (in the same way {{dataindex}} is escaped already in the template)

  23. Thomas says:

    Hi Ed,

    I am glad that I found your site… great extension!

    Is there an easy way or config-option to hide certain columns when printing.
    Especially when I use custom renderers for some of the grids content (e.g. to render icons instead of text), the printable html-table will show only braces or empty cells…

    Therefore I would love to “switch off” those columns when printig.
    Cheer Thomas

  24. Geoffrey says:

    Hi
    There are no context of htmleditor when I printed the UI. I want to know whether there have other setting?

  25. Geoffrey says:

    the error message was “Microsoft JScript runtime error: ‘Ext.ux.Printer’ is null or not object” when I run the app in IE8.

  26. Reinier says:

    Great, this is exactly what I needed. Thanks!

    It would be great if the column styles (the css-property in the column model) were used when printing 😉

  27. maxeman says:

    Is it possible to use this plugin to print a panel containing 3 different grids?
    I have a summery page showing 3 tables writen in pure html, I like to tranform this into a extjs panel with 3 gridpanels.
    Is it possible to use the plugin to print a panel like that?

  28. Tech Kone says:

    Excellent extension! I have used it, in a modified way to render a grid as part of a form i am printing. The issue that i have is that it only prints the first page of my content,and the second page is entirely blank. It might not be related to your component but i was wondering if you had any idea, like if you wanted to print a grid that was more than one page long.
    Thanks in advance!

  29. Matt Bittner says:

    Has anyone made this work with a TreePanel? Thanks.

    Matt Bittner

  30. Matt Bittner says:

    Never mind about the TreePanel question. Sorry.

    Matt Bittner

  31. Pingback: extjstutorial.org

  32. Abdul Malik says:

    I was try below code to my extjs form, but it does not work, how to make it work, am I miss something

    var panel = new Ext.Panel({
    html: {
    tag: ‘ul’,
    chidren: [
    {tag: ‘li’, text: ‘Item 1’},
    {tag: ‘li’, text: ‘Item 2’},
    {tag: ‘li’, text: ‘Item 3’}
    ]
    }
    });

    Ext.ux.Printer.print(panel);

    Thanks

  33. Linus says:

    Thanks Ed for this extension. I am generating the rownumber by doing this theRowNumberer = new Ext.grid.RowNumberer({header: ‘#’, width: 23}) in the column model. The grid is rendered with the row number.

    However the print preview shows ‘{}’ for the rownumber. Any help will be greatly appreciated.

    Thanks!

  34. Anonymous says:

    @Abdul Malik: You really need to read the README file, everything is explained!

    You are missing the renderer and the renderer registration before printing!

    Something like that..

    Ext.ux.Printer.PanelRenderer = Ext.extend(Ext.ux.Printer.BaseRenderer, {
    generateBody: function(panel)
    {
    return String.format(“{0}”, panel.body.dom.innerHTML);
    }
    });

    Ext.ux.Printer.registerRenderer(‘panel’, Ext.ux.Printer.PanelRenderer);

    and then.. you can

    Ext.ux.Printer.print(panel);

  35. Aggie says:

    Hi guys!!

    Has anyone tried printing a panel which has a gridpanel in it?it prints the grid just well except for the grid headers which are treated as separate divs and not a grid row.
    How can i sort this out because the headers are floating out of the grid.

    Tahnks!

  36. Desiree says:

    Hi!

    Does this work with PivotGrid?

    Thanks!

  37. Lord says:

    Hi, Someone tried to create a render to PivotGrid, or have any idea how to do it?
    Regards.

  38. Ed Spencer says:

    This thing was done before PivotGrid so had never supported it. In principle I don’t see why it couldn’t be updated to do so, but my time is rather constrained by Ext JS 4.1 and Sencha Touch 2.0 🙂

    Feel free to fork/submit patches

  39. Christian Cypert says:

    Hello, I am in the process of implementing the printer component, but have a bit of an issue. First I must say javascript (and EXT for that matter) is not my normal language so I’m sure I’m doing something boneheaded. I have created a grid with a print button. In the handler for the print button I call the Printer function. The problem is that the printed page is blank. I have 4 lines of data in my grid, but the printed page about “about:blank” as the only text on the page. Below is the code I have for the handler function in my button. I’ve played around with a few lines of code to see if I can make things work, so I may have added code that is not needed.

    handler: function(){
    Ext.ux.Printer.PanelRenderer = Ext.extend(Ext.ux.Printer.BaseRenderer, {
    generateBody: function(panel) {
    return String.format(“{0}”, panel.body.dom.innerHTML);
    }
    });
    Ext.ux.Printer.registerRenderer(“panel”, Ext.ux.Printer.PanelRenderer);
    Ext.ux.Printer.print(stockProductList.grid);
    },

    I have also included the proper lines in the header of the web page to load the correct javascripts.

    Thanks

  40. Rus says:

    Thanks, for good solution. Though it do not works in Chrome – it shows “Print preview failed” and printing “CreatePreviewDocument got 0 page count” to browser stdout. Firefox works perfectly.

  41. James says:

    This is great! And it worked after I changed a bit.

    Actually, I spent some time to debug and finally removed a piece of code which is calling getTitle method and that caused the error – Object doesn’t support this property or method.

    IE gives me error happening at Line 52 but is not.

    I used Web Developer in Firefox and found that error.

    I am using EXTJS3.0. So I don’t know if it’s because the version is old or something.

    Anyways, this is great help on my project! Thanks!

  42. Manel says:

    Hello i’m trying your ext.ux.printer with extjs 4.0.7 but it destroys my css layout in the page and takes this error: h.owner.up(“tablepanel”) is undefined

    Is it compatible with ext 4.0.7 ?

    thanks.

  43. Ed Spencer says:

    @Manel I haven’t upgraded the plugin to work with 4.x yet, perhaps once Sencha Touch 2 GA is out I’ll spend a little time on that

  44. Dennis says:

    Hello,

    it is very nice plugin. But as I understand it can print only one component at time. What is if I would like to print a window with a GridPsnel, FormPanel, InputFields in it?

  45. ankit says:

    Hello,
    This is really a very good plugin.
    I am trying to use it for grid with pagination.
    How can i get all the data(paginated data) in print? I can only get first page data right now.
    FYI, i am using extjs4.
    Can you please help me with the issue?

  46. Prastiyo Beka says:

    Hello,
    I have a form and i want print it but i can’t do that, so what i have to do?
    any ux for print form ? or something else maybe?
    please i need your help.

    Thanks

  47. madhuri says:

    i am not able to print panel or grid or tree.
    my extjs version is 4. please help
    i found ext.ux.printer plugin for printing tree and grid but it is not supported by extjs 4.x
    Tell me if there is any in built method or cofig or property for printing in extjs 4
    please help me out with the solution

  48. Farish says:

    Hi,

    I was trying to use your extension for Ext JS 4.0.7 but it didnt work out. I am getting an error from ext-all-debug.js when I include Printer.js:

    TypeError: me.owner.up(“tablepanel”) is undefined
    [Break On This Error]

    s = me.owner.up(‘tablepanel’).verticalScroller;

    ext-all-debug.js (line 75573)

    Does this plugin work on latest versions of Ext JS? It doesnt seem to have been updated since a long time.

    Thanks and regards,
    Farish

  49. Ram says:

    Hi, Can you guide me how to print form along with metadata and data same

  50. Razgriz says:

    Did anyone manage to make this work in ExtJS 4.2?

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: