Printing grids with Ext JS

July 26, 2009 by Ed Spencer · 56 Comments 

Grids are one of the most widely used components in Ext JS, and often represent data that the user would like to print. As the grid is usually part of a wider application, simply printing the page isn’t often a good solution.

You could attach a stylesheet with media=”print”, which hides all of the other items on the page, though this is rather application-specific, and a pain to update. It would be far better to have a reusable way of printing the data from any grid.

The way I went about this was to open up a new window, build a table containing the grid data into the new window, then print it and close. It’s actually pretty simple, and with a bit of CSS we can even get the printable view looking like it does in the grid.

Here’s how you use it (this is a slightly modified version of the Array Grid Example):

var grid = new Ext.grid.GridPanel({
  store  : store,
  columns: [
      {header: "Company",      width: 160, dataIndex: 'company'},
      {header: "Price",        width: 75,  dataIndex: 'price', renderer: 'usMoney'},
      {header: "Change",       width: 75,  dataIndex: 'change'},
      {header: "% Change",     width: 75,  dataIndex: 'pctChange'}
      {header: "Last Updated", width: 85,  dataIndex: 'lastChange', renderer: Ext.util.Format.dateRenderer('m/d/Y')}
  ],
  title:'Array Grid',
  tbar : [
    {
      text   : 'Print',
      iconCls: 'print',
      handler: function() {
        Ext.ux.GridPrinter.print(grid);
      }
    }
  ]
});

So we’ve just set up a simple grid with a print button in the top toolbar. The button just calls Ext.ux.GridPrinter.print, which does all the rest. The full source code that this example was based upon can be found at http://extjs.com/deploy/dev/examples/grid/array-grid.js.

The source for the extension itself is pretty simple (download it here):

If you look at the source above you’ll see it includes a ‘print.css’ stylesheet, which can be used to style the printable markup. The GridPrinter expects this stylesheet to be available at /stylesheets/print.css, but this is easy to change:

  //add this before you call Ext.ux.GridPrinter.print
  Ext.ux.GridPrinter.stylesheetPath = '/some/other/path/gridPrint.css';

Finally, here is some CSS I’ve used to achieve a grid-like display on the printable page:

html,body,div,dl,dt,dd,ul,ol,li,h1,h2,h3,h4,h5,h6,pre,form,fieldset,input,p,blockquote,th,td{margin:0;padding:0;}
img,body,html{border:0;}
address,caption,cite,code,dfn,em,strong,th,var{font-style:normal;font-weight:normal;}
ol,ul {list-style:none;}caption,th {text-align:left;}h1,h2,h3,h4,h5,h6{font-size:100%;}q:before,q:after{content:'';}

table {
  width: 100%;
  text-align: left;
  font-size: 11px;
  font-family: arial;
  border-collapse: collapse;
}

table th {
  padding: 4px 3px 4px 5px;
  border: 1px solid #d0d0d0;
  border-left-color: #eee;
  background-color: #ededed;
}

table td {
  padding: 4px 3px 4px 5px;
  border-style: none solid solid;
  border-width: 1px;
  border-color: #ededed;
}

This technique could easily be adapted to print any component that uses a store – DataViews, ComboBoxes, Charts – whatever. It just requires changing the generated markup and stylesheet.

Related posts

About Ed Spencer
Software Architect at Sencha Inc where I lead the development of Ext JS and supporting projects. A longtime lover of JavaScript and related geekery, currently living in Palo Alto.

Comments

56 Responses to “Printing grids with Ext JS”
  1. Anonymous says:

    Nice work Ed.

  2. Lloyd K says:

    Excellent work and happy birthday!

  3. Andrew says:

    Thanks for this extremely useful bit of code!

  4. Loiane says:

    Excellent work!
    I was looking for something like this and it is perfect!

  5. Night says:

    Excellent work! Спасибо, подрочил!

  6. Anonymous says:

    Thanks for the code , but i get the following error

    grid.getColumnModel() is not a function

    How can i fix this ? thanks in advance

  7. Dan Ellison says:

    This script works flawlessly using Firefox 3 – Explorer 7 however gives me a new window for the briefest time and the the new window simply vanishes and no print dialogue is ever presented. Tried setting the options for a “open popups in new tab” but didn’t change anything. Any ideas what is happening (other than good old microsoft strikes again….?) Thanks a million.

  8. Hee says:

    I need to pass some parameters over to print. How can I do so? Thank you.

  9. Dan says:

    This script works great, however I noticed a subtle bug in firefox if you would want to open a print view that does not print the document immediately. (ie remove calls to win.print() and win.close()) Firefox will continue to “loading” the page indefinitely. In order to correct add:


    win.document.write(html);
    win.document.close();

  10. Ahmad says:

    The printer friendly table always shows all the columns in the store, even though if they were hidden, how can I show only the visible columns?

  11. Ahmad says:

    @Dan
    If you want the new window/tab to not close immediately then you can remove the following line:
    win.close()

  12. kmil0cv says:

    Excellent work!, Thanks for the code.

    but what about if the grid has a paging toolbar ?
    this scripts only prints the data in the active page.
    any idea?

    maybe reloading the store without any limit,start parameter ??

    cheers!

  13. Alan says:

    For those that were having trouble with IE, I think the following changes fix this issue.

    1. Move the print trigger to the onload():
    ”,
    remove:
    win.print();

    2. Change the:
    win.close();
    to
    win.document.close();
    as suggested by another commenter.

    win.print() doesn’t seem to work in IE for a dynamically created document, and the win.document.close() is essential for the onLoad event to work in IE. This solution does not end up automatically closing the window after printing, but I prefer that behavior.

  14. Alan says:

    I’m not sure what happened to the onLoad line in my earlier comment, basically you want to call window.print() from the body tag of the generated HTML.

  15. Ed Spencer says:

    I’ve updated the Github gist with the window.document.close() as suggested by Dan and Alan. I suggest you check out Ext.ux.Printer instead though as it’s a more comprehensive plugin that can be applied to any component (see http://edspencer.net/2009/07/extuxprinter-printing-for-any-ext.html)

  16. Ben McLendon says:

    I’ve tried both of your grid printing solutions and I have the same issue with both. I get the grid headers but no rows on the printout. I must be missing something. Thanks!!!

  17. Luiz Feliph says:

    HI,
    Nice work! Just a thing: in the link to the source code, this:
    ” + grid.title + ”,
    is this:
    ” + grid.getTitle() + ”,

    no big deal =)

  18. chrispy says:

    Hi “Ben” I think I have solved your problem with the rows not appearing, are you using ajax data?

    If so, the grid is being sent to print before the data store has gotten the data, to fix this issue you can do the following:

    ds.load();

    ds.on({
    ‘load’:{
    fn: function(store, records, options){
    Ext.ux.Printer.print(grid);
    },scope:this
    }
    });

    This basically waits for the datastore to load and then runs the print option.

  19. easy says:

    Hi Ed Spencer,

    Am new to this but its really work and excellent. I have few inquiry, what if the grid has pagination. Where i want to print all the pages in the grid panel. As i tested the scripts only print the active page or the selected page. Any Idea how to do this?

    Thank you so much for all your favorable action taken.

  20. Ed Spencer says:

    @easy you’d need to either load all of the records first (set the pageSize to a very high number), or programmatically load each page and print it. The first solution is obviously better.

  21. easy says:

    Thanks for the reply Ed Spencer… Actually am still new to EXTJS, Is it possible if u can help me how to do with the first solution. Just a draft script.. if possible. Thank you so much.

  22. Arthur Park says:

    Great stuff!! Thank you for sharing this wonderful piece of code.

    You can also bring in the same styling from extjs grid to this print friendly table by changing
    bodyTpl: new Ext.XTemplate(
    ”,
    ”,
    ‘\{{dataIndex}\}’,
    ”,

    )
    to
    bodyTpl: new Ext.XTemplate(
    ”,
    ”,
    ‘\{{dataIndex}\}’,
    ”,

    )
    Don’t forget to add the css class to thie print friendly page.
    I use this for aligning text.

    One problem I have, is that I want to retrieve css class from each row which I assigned from ‘getRowClass’, but I am out of luck. Any idea?

  23. Arthur Park says:

    Oops, that looks weird. I don’t usually write codes in blogs so forgive me for that.

    Bottom line of my tip is to add class=”{id}” to <td> in the bodyTpl so it looks like
    <td class=”{id}”>

    Hope this one shows alright.

  24. tolis says:

    To work in chrome as well change the following:
    var win = window.open(”, ‘printgrid’);

    win.document.write(html);
    win.document.close();

    win.print();
    win.close();

    to the follwing
    var win = window.open(”, ‘printgrid’);
    win.document.write(html);
    win.document.close();
    win.focus();
    win.print();
    win.focus();
    win.close();

  25. Marco says:

    Sorry for my English.

    I have one error. In my grid example, one column is renderered by this function:

    faltas = function(value, metaData, record, rowIndex, colIndex, store) {
    if( value == 0 ) {
    metaData.css = “icon-cell icon-faltas1″;
    } else if( value > 3 ) {
    metaData.css = “icon-cell icon-faltas2″;
    } else {
    metaData.css = “icon-cell icon-faltas3″;
    }
    }

    then in this line of code:

    convertedData[key] = column.renderer ? column.renderer(value) : value;

    I see this error in firebug console:

    metaData is undefined
    metaData.css = “icon-cell icon-faltas1″;

    Any idea? how i can resolve this situation?

    Thanks

  26. Robin says:

    Hi, Ed Spencer
    this is great!, and I love this portion of code, any way I want to know is it possible to print grid with grouping view?

    Thanks,

  27. pxavier says:

    Do not confuse this is not an impression of a gridpanel is just the impression of a store, because if you run a sort on the grid or remove columns printed the same.

  28. Thank you, I used it in my application

  29. Aladdin says:

    Nice work Ed Spencer ,

    I am trying to do the same thing to print the whole page , it is only printing only one page and the rest of the data are not showing when I do print preview .
    Any idea ?

    I tried this :
    xtype: ‘button’,
    text: ‘Print’,
    handler: function () {
    /*var oNewDoc = document.open(”text/html”, “replace”);
    var sMarkup = “”+Ext.getCmp(’main’).body.dom.innerHTML+”";
    oNewDoc.write(sMarkup);*/
    console.debug(Ext.getCmp(’main’).body.dom.innerHTML);
    var win = window.open(”", “”); // a window object

    var doc = win.document;
    doc.open(”text/html”, “replace”);
    doc.write( ”,
    ”,
    ”,
    ”,
    ”,
    ” + ” + ”,
    ”,
    ”,
    Ext.getCmp(’main’).body.dom.innerHTML,
    ”,
    ”);
    doc.close();

    Thanks,

  30. Ian says:

    For those who want to print the whole grid and not just the current page here is what I did:

    handler: function() {
    store.load({
    callback: function() {
    Ext.ux.Printer.print(panel);
    store.load({params:{start:0, limit:15}});
    }
    });
    }

    Explanation:
    My grid initially shows 15 items per page.
    When you press the Print button the store is first reloaded with no limit.
    A Callback function is used to make sure the store has finished loading before printing.
    After printing the store is reloaded with the 15 item limit.

    Note: The above function will always return to the first page after printing. If you want to return to the current page after printing then you could use something like this, where bbar refers to the paging toolbar.

    handler: function() {
    var cursor = bbar.cursor;
    store.load({
    callback: function() {
    Ext.ux.Printer.print(panel);
    store.load({params:{start:cursor, limit:15}});
    }
    });
    }

  31. Dan Downs says:

    Great work, this saved me a ton of time. I made a couple tweaks I wanted to share.

    I added the ability to pass in a separate column model for printing and to pass the record along with the value to the renderer functions.

    print: function(grid, columns) {
    var columns = columns ? columns : grid.getColumnModel().config;

    convertedData[key] = column.renderer ? column.renderer(value, item) : value;

    example usage:

    Our company grid has a lot more fields than whats shown here, but by overriding the column model to use and renderers I was able to combine several columns like address from “Address, City, State, Postal, Country” into one column while leaving them separate on the grid for sorting reasons.

    var printPreviewClick = function() {
    var columns = [
    {header: '', dataIndex: 'disabled', renderer: printDisabled}
    ,{header: 'ID', dataIndex: 'companyID', id: 'companyID'}
    ,{header: 'Name', dataIndex: 'officialName', renderer: printName}
    ,{header: 'Address', dataIndex: 'address', renderer: printAddress}
    ,{header: 'Contact', dataIndex: 'contactPerson', renderer: printContact}
    ,{header: 'Domains', dataIndex: 'domains', renderer: printDomains}
    ];

    Ext.ux.GridPrinter.print(CompanyGrid, columns);
    };

    function printAddress(value, record) {
    value = String.format(’{0}{1}, {2} {3}{4}’,
    record.get(’address’),
    record.get(’city’),
    record.get(’state’),
    record.get(’postal’),
    record.get(’country’) ? ‘ – ‘ + record.get(’country’) : ”);
    return value;
    }

  32. Nohemus says:

    Great work !! Very impressive.

    When the user of a grid hides a column, this column is still printed.

    Does anybody know how don’t print an hidden column ?

    Thanks

  33. Miko says:

    Hi,

    On September 14, 2010 at 5:28 pm the user Marco posted an interesting question regarding to how the GridPrinter fail when the renderer use metadata.css …. is there a solution to fix that?

    thank you
    Miko

  34. Ola says:

    Hi,

    about Marcos post, I did like this.

    In GridPanel.js, under “//apply renderers from column model” I check which column contain the metadata.css and for this column I choose to use the ‘value’ instead of the function ‘cloumn.renderer’ , as:

    if (column.dataIndex == key) {
    var myTempVal;
    if (column.dataIndex == ‘myColumnName’) {
    myTempVal = value;
    }else {
    myTempVal = column.renderer(value, null, item);
    }
    convertedData[key] = column.renderer ? myTempVal : value;
    return false;
    }

  35. Miko says:

    Regarding my previous post a workaround for the issue: in the renders I validate the existence of the metadata parameter before to use it… and with that the plugins work. Would be nice if the plugin could control the metadata parameter… today is just passing “null” to the renders.

  36. Abeu says:

    Excellent work!
    but i get the following error

    grid.getColumnModel() is not a function

    is there a solution to fix that?
    thank you
    Abeu

  37. lem says:

    Thank you for this great work,

    I want to print grouped grid,but i do not know how to handle this.

    Any idea?

    with best regards,

  38. Ola says:

    Hi,

    about lem post (Printing GridPanels with GroupingView and GroupSummary plugin), I found this on Rahul Singlas web site and Its working great for me:

    http://www.rahulsingla.com/blog/2010/10/extjs-printing-gridpanels-with-groupingview-and-groupsummary-plugin

    Thanks alot Ed Spencer and Rahul Singlas – you make our life easier ! :)

  39. Aggie says:

    Am using ext4 and would want to print some panels for my reports.has anyone implemented this for ext4?
    Thank you for this excellent work!!!

  40. Ed Spencer says:

    @Aggie not that I’m aware of, though this plugin plus the exporter seem to be popular enough that we’re considering merging them into an upcoming version of the framework

  41. Aggie says:

    Yeah, merging them would really help.
    keep us posted when either the exporter or printer for ext4 are available.
    Thanks alot!!

  42. kprk says:

    Hi Ed,

    Appreciate your effort. I am able to print in FF, but i am not able to print in Chrome. I followed the code what tolis said in the forum, but I am ,still , unable to do this. Could you please guide me how can I make this working for chrome.

  43. Yaron Yogev says:

    Thanks Ed for this very useful solution !

    Below are the changes to make it work with ExtJS 4.

    HTH
    Yaron Yogev

    Index: Ext.ux.GridPrinter.js
    ===================================================================
    RCS file: /arch/cvs/it/lib/extjs/ux/Ext.ux.GridPrinter.js,v
    retrieving revision 1.2
    diff -u -r1.2 Ext.ux.GridPrinter.js
    — Ext.ux.GridPrinter.js 1 Aug 2011 14:31:17 -0000 1.2
    +++ Ext.ux.GridPrinter.js 2 Aug 2011 10:24:08 -0000
    @@ -24,7 +24,7 @@
    print: function(grid) {
    //We generate an XTemplate here by using 2 intermediary XTemplates – one to create the header,
    //the other to create the body (see the escaped {} below)
    - var columns = grid.getColumnModel().config;
    + var columns = grid.columns;

    //build a useable array of store data for the XTemplate
    var data = [];
    @@ -92,7 +92,7 @@
    headerTpl: new Ext.XTemplate(
    ”,
    ”,
    - ‘{header}’,
    + ‘{text}’,
    ”,

    ),

  44. Sherry says:

    Hi,
    Iif I have five items grid data, but i want to print a item in one page. So, there are five pages to be printed, any ideas about that?
    Thanks.

  45. Bratin says:

    Due to 508 complience, I want to implement table (html table containing data) with sorting, searching functionality using extjs. Using above example I was able to generate table structure. But I need help to implement sortable/ searchable feature. I am new in ext js. Any idea?

  46. Bratin says:

    how to create sortable table ( not grid) using xtemplate in extjs?

  47. Andrés Serrón says:

    Clean, well made.
    I was about coding something that builds a printable markup and then you come with this clean solution.

    Some ideas.
    - Open the solution so we can contribute with more renderer extensions.
    - Think about a plug in version.
    - Meta tags parsing in template: model external html, include it and compile it out of script.

    what you think?

    Pd: thanks for your work.

  48. Mir says:

    Hello,

    Is it possible to print exact structure if grid contains grouping.

    I mean that I need to print after I have grouped the data by certain columns.

  49. masoud says:

    i used it , but it doesn’t work for mine . error is :
    me.owner.up(”tablepanel”) is undefined

  50. James says:

    Thank you for this!

    I commented out these 2 lines so our editor can print or copy/paste big table to excel.

    win.print();
    win.close();

    One drawback of my change is that the page keeps loading.

    James

Trackbacks

Check out what others are saying about this post...
  1. [...] gera uma página em HTML apenas com as informações do Grid. Porém com uma diferença: o GridPrinter é um plugin Third Party (de terceiros) para o ExtJS, ou seja, não preciso fazer uma requisição ao servidor para [...]

  2. Printing grids with Ext JS…

    Grids are one of the most widely used components in Ext JS, and often represent data that the user would like to print. As the grid is usually part of a wider application, simply printing the page isn’t often a good solution.

    You could attach a styles…

  3. [...] Plugin  grid printer  grid printer plugin  print button Tweet Ed Spencer created a plugin that is capable of creating a print version of an ExtJS grid. This plugin was originally created for ExtJS 3.x. I ported it to ExtJS 4, in case someone need [...]

  4. [...] Ed Spencer criou um plugin que é capaz de criar uma versão para impressão do conteúdo exibido em…. Esse plugin foi criado orginalmente para Ext JS 3 e resolvi fazer a migração para ExtJS 4, caso alguém precise. [...]

  5. [...] Ed Spencer criou um plugin que é capaz de criar uma versão para impressão do conteúdo exibido em…. Esse plugin foi criado orginalmente para Ext JS 3 e resolvi fazer a migração para ExtJS 4, caso alguém precise. [...]



Speak Your Mind

Tell us what you're thinking...
and oh, if you want a pic to show with your comment, go get a gravatar!