Ext.ux.Printer – printing for any ExtJS Component
July 28, 2009 51 Comments
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';
Awesome addon, found it easy to implement and use was just curious about grid striping rows I've toyed with it with minimal success
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
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
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.
Ed, this is brilliant!!!
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!!!’;
BTW: Ed, I can not find a email address to you on the site : (
I just started using the component in an internal app. Thank you for sharing.
Ed, this is a terrific extension! Thanks much!
Pingback: Ext.ux.Exporter – export any Grid to Excel or CSV : Ed Spencer
Is there an ambition to extend it for Grouping Store???
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.
Hi,
if i want print ext.window?
Thank’s you help me a lot
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();}
Great Component! Thanks! But It doesn’t work in Opera for me. How I can fix it?
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.
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);
@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.
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!
Hmm i guess all the slashes in the code made my comment go strange…
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)
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
Hi
There are no context of htmleditor when I printed the UI. I want to know whether there have other setting?
the error message was “Microsoft JScript runtime error: ‘Ext.ux.Printer’ is null or not object” when I run the app in IE8.
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 😉
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?
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!
Has anyone made this work with a TreePanel? Thanks.
Matt Bittner
Never mind about the TreePanel question. Sorry.
Matt Bittner
Pingback: extjstutorial.org
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
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!
@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);
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!
Hi!
Does this work with PivotGrid?
Thanks!
Hi, Someone tried to create a render to PivotGrid, or have any idea how to do it?
Regards.
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
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
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.
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!
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.
@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
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?
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?
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
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
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
Hi, Can you guide me how to print form along with metadata and data same
Did anyone manage to make this work in ExtJS 4.2?