PDA

View Full Version : ExtJS 4: Grid Printer Plugin



loiane
7 Sep 2011, 5:36 AM
Hi,

I ported GridPrinter plugin to ExtJS 4.
This plugin was originally written by Ed Spencer.

Code: https://github.com/loiane/extjs4-ux-gridprinter
Demo: http://loianegroner.com/extjs/examples/extjs4-ux-gridprinter/
Blog post: http://loianegroner.com/2011/09/extjs-4-grid-printer-plugin

crysfel
7 Sep 2011, 9:11 AM
This is great, I was planing on porting this plugin to ext4 but you did it!

Thanks for share.

zacware
8 Sep 2011, 8:28 PM
Thank you! Really missed having this.

foxmarco
9 Sep 2011, 9:06 AM
but in case of paging?

loiane
23 Sep 2011, 3:56 AM
but in case of paging?

The plugin will only print what the grid is displaying at the time.
To print all the records, you have to change the plugin and load all the records into the store, or you can create a server side solution.

hschaefer123
29 Sep 2011, 12:41 AM
Hi Loiane,
thanks for the migration.

I like to see that the code quality of migrated extensions is getting better and better and Ext 4 has the possibility to produce same quality with less code ;-)

Currently Grid Printer does not support TemplateColumns -> XTemplate Exception.

I added support this way


Ext.each(columns, function(column) {
if (column.dataIndex == key) {
// template column support
if (column instanceof Ext.grid.column.Template) {
convertedData[key] = column.tpl.apply(item.data);
} else {
convertedData[key] = column.renderer ? column.renderer(value) : value;
}
}
}, this);

Cheers Holger

loiane
10 Oct 2011, 2:47 PM
Thanks!

I will update the plugin code with these new fixes!

parkcity
11 Oct 2011, 1:41 AM
I am using chrome and the code doesn't print automatically. In chrome I get the notification.."Print Preview failed". The code works fine when printAutomatically is set to false.

mfruizs2
14 Oct 2011, 12:20 AM
First: Thx 4 ur great support, mates!

Second: For @parkcity, to delete this error, u need to erase or commented the windows internal command to close the windows, then, it will run nice again :)

Now, my question :) I need to print all the grid, but not all the grid print on the current screen, else all data store. Then, how could I return all the storage on a "grid.panel" that is the parameter i need to ?

thx 4 ur time!

cya!

PS: sorry if i didnt explaned very well :(

hschaefer123
14 Oct 2011, 1:55 AM
A little addon to the htmlMarkup with table headers (THEAD) and table body (TBODY) tags will allow printing table head on each page (if printing large grids that are printed on different pages).

Concerning question printing large store, the grid prints the binded store. So make sure the store contains all data and you do not use filtering or paging (ex. paging plugin) or paging should be a very large value.

This solution should not be a genrall solution for printing very large data sets! In such a case you should generate print output on server side and maybe download it as PDF.

The plugin is thought as a quick and easy solution to print the visible grid part, including custom renderers, etc.

Currently all columns are printed, but it is also possible to filter hidden column, or prior print to hide some columns that contain html markup not needed to be printed in a later version.


var htmlMarkup = [
'<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">',
'<html>',
'<head>',
'<meta content="text/html; charset=UTF-8" http-equiv="Content-Type" />',
'<link href="' + this.stylesheetPath + '" rel="stylesheet" type="text/css" media="screen,print" />',
'<title>' + grid.title + '</title>',
'</head>',
'<body>',
'<table>',
'<thead>',
headings,
'</thead>',
'<tbody>',
'<tpl for=".">',
body,
'</tpl>',
'</tbody>',
'</table>',
'</body>',
'</html>'
];

mfruizs2
14 Oct 2011, 2:37 AM
Thx 4 the reply.

It's interesting ... How could i need to rewrite the code on the printer plugin to put the head on all the pages ? because with only adding <thead> and </thead> not do it.

thx again 4 ur help!

hschaefer123
23 Oct 2011, 11:35 PM
Hi mfruizs2,
i do not know if this works in all browsers as expected, but you are right.

You only need the addtional THEAD/TBODY markup to get this working in firefox.
This is standard html behavior.
I did not check this thing against all browsers because it is only additional markup (nice to have),

So if you browser did not cache the script and your table is printed on at least 2 pages
each page should have its own column description (headers) on top.

Cheers Holger

mfruizs2
25 Oct 2011, 6:54 AM
Ok thx 4 all. i'm thinking that i need to re-code the CSS to get it.

cya!

craigsimons
24 Nov 2011, 2:48 PM
Viewing source in Chrome will crash the browser. Firefox doesn't crash, but source is blank.

venkateshns
28 Nov 2011, 2:47 AM
HI All,
Can anybody tell me how to print a form panel ?

Regards,
Venkatesh

rjsquire
3 Jan 2012, 2:04 PM
Using the example from the distribution, I found that the css was not getting applied when printAutomatically is true. When it is false, the page never finishes loading. All the content is displayed, but the loading indicator of the browser is still moving.

To fix this, the stream opened to write to the document needs to be closed. One line is added to the plugin right after the data is written to the document.


win.document.write(html);
win.document.close(); // this line is new and closes the stream
if (this.printAutomatically){
win.print();
win.close();
}

Once that is in place, the printable view works perfectly whether or not printAutomatically is set.

amanp
23 Jan 2012, 12:59 AM
This plugin doesn't support for grid panels with grouped headers...

caballero
22 Feb 2012, 11:44 PM
god bless you hschaefer123


Your code snippet was a life saver.


Loraine, you mentioned that you would put his fix into the source. I highly recommend you do. I spent a good hour and a half trying to get this to work on multiple grids.


Great tool.


Thanks again.

masoud_tamizy
23 Feb 2012, 1:34 AM
very good plugin :)

user ext
24 Feb 2012, 8:22 AM
This plugin doesn't support for grid panels with grouped headers... This variant for grouped headers ( column group or nested headers) and grid grouping.
print: function (grid)
{

var columns = grid.headerCt.getVisibleGridColumns(false);
//drop first empty column (when grid groupped)
if (columns[0].dataIndex == null && columns[0].items.length == 0) columns.shift();
//build a useable array of store data for the XTemplate
var data = [];
grid.store.data.each(function (item)
{
var convertedData = [];
//apply renderers from column model
for (var key in item.data)
{
var value = item.data[key];
Ext.each(columns, function (column)
{
if (column.dataIndex == key)
{
var colIndex = column.getIndex();
convertedData[key] = column.renderer ? column.renderer.call(grid, value, null, item, null, colIndex) : value;
}
}, this);
}
data.push(convertedData);
});

//create nested headers as html (not used headerTpl)
var nr = 0, rows = [[]];
var fn = function (item, index, all)
{
if (item.dataIndex == null)
{
var cols = item.items.items;
if (cols.length > 0 && !item.hidden)
{
rows[nr].push('<th colspan="' + cols.length + '"><div align="center">' + item.text + '</div></th>');
nr++; if (nr == rows.length){ rows[nr] = []; }
Ext.each(cols, fn);
nr--;
}
}
else
{
if (!item.hidden) rows[nr].push('<th{0}>' + item.text + '</th>');
}
}
Ext.each(grid.columns, fn);
Ext.each(rows, function (item, index, all)
{
item.unshift('<tr>'); item.push('</tr>');
all[index] = Ext.String.format(item.join(''), ' rowspan="' + (all.length - index) + '"');
});
var headings = rows.join('');
var body = Ext.create('Ext.XTemplate', this.bodyTpl).apply(columns);

var htmlMarkup =
[
'<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">',
'<html>',
'<head>',
'<meta content="text/html; charset=UTF-8" http-equiv="Content-Type" />',
'<link href="' + this.stylesheetPath + '" rel="stylesheet" type="text/css" media="screen,print" />',
'<title>' + 'table: ' + grid.store.storeId + '</title>',
'</head>',
'<body>',
'<table>',
headings,
'<tpl for=".">',
body,
'</tpl>',
'</table>',
'</body>',
'</html>'
];

var html = Ext.create('Ext.XTemplate', htmlMarkup).apply(data);

//open up a new printing window, write to it, print it and close
var win = window.open('', 'printgrid');
win.document.write(html);
win.document.close();

if (this.printAutomatically)
{
win.print();
win.close();
}
},

vicvolk
29 Mar 2012, 9:15 AM
"This variant for grouped headers ( column group or nested headers) and grid grouping".

Unfortunately, it does not work with three and more level headers.

philance
1 Apr 2012, 2:54 PM
First of all, thanks a lot for great plugin.

Btw, I implement grid with remote store and paging. At any time, there are only pageSize records, and hence when print, it only print those pageSize records. How can I modify your plugin to make it print the whole remote store.

Thanks a lot in advance.

navvn
8 May 2012, 12:28 AM
Any solution to make a xtype rownumberer working? Right now it outputs only {}

talha06
17 May 2012, 10:18 PM
Hi everyone,
Thanks a lot Loiane and Ed for this great extension. =D> I'm getting the error that I added below while using this with ExtJS 4.1, I'll be happy if someone can help me.
Thanks in advance.
With regards,
T


missing ) in parenthetical
if ((v=fm.0(values['margin']))!==undefined) out.push(v+'')

austin1030
20 May 2012, 8:08 AM
I get this error

Uncaught SyntaxError: Unexpected number

Any idea?

predator
23 May 2012, 6:27 PM
Hi everyone,
Thanks a lot Loiane and Ed for this great extension. =D> I'm getting the error that I added below while using this with ExtJS 4.1, I'll be happy if someone can help me.
Thanks in advance.
With regards,
T


missing ) in parenthetical
if ((v=fm.0(values['margin']))!==undefined) out.push(v+'')

I think i have the same error.

missing ) in parenthetical
http://project2.dev/libs/ext4/ext-all.js
Line 22

byu_risk3
14 Jun 2012, 1:37 PM
This plug in doesn't seem to work with action columns. In Printer.js, some of the algorithms under the print() function that deal with the columns throw an error when it gets to the action column I think.

talha06
15 Jun 2012, 5:51 AM
This plug in doesn't seem to work with action columns. In Printer.js, some of the algorithms under the print() function that deal with the columns throw an error when it gets to the action column I think.
I tried that before, it still gives error..

byu_risk3
15 Jun 2012, 9:31 AM
I tried that before, it still gives error..

I'm not sure what you are referring to when you say you 'tried that before'...

I was able to get the printer plugin to work with action columns by hacking the code a little bit. I also changed the code so that the grid will only display the columns visible to the user.

Here is my modification for Printer.js



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 = [];

//account for grouped columns
Ext.each( grid.view.headerCt.getVisibleGridColumns() , function(c) { // byu_risk3 modification - only print visible columns that user sees
// Ext.each( grid.columns , function(c) { // Original code
if( c.xtype != "actioncolumn" ){ // byu_risk3 modification - prevent action columns from being included with other columns
if(c.items.length > 0) {
columns = columns.concat(c.items.items);
} else {
columns.push(c);
}
}
});
// ...etc


Hope this helps someone who gets errors with action columns. :)

talha06
15 Jun 2012, 10:58 AM
@byu_risk3
I mean even if I don't have an 'actioncolumn', it stils gives same error '
Uncaught SyntaxError: Unexpected number'.

flex62ryz
18 Jul 2012, 4:36 AM
For browsers based on WebKit engine when print window opened the title of window has value "Untitled". Fix it for safari you can swap this code:

var win=window.open('','printgrid');
on this:

var win=window.open('about:blank','printgrid');

For Chrome this solution fixes problem not fully

flex62ryz
18 Jul 2012, 5:31 AM
In column values of print grid instead of empty values displays string with "null" text. I fix it by replace code:
line 108

var body =Ext.create('Ext.XTemplate',this.bodyTpl).apply(columns);
on this

var body = Ext.htmlDecode(Ext.create('Ext.XTemplate',this.bodyTpl).apply(columns));

and replace this:
line 248

'<td>\{{dataIndex}\}</td>'
on this

'<td>&lt;tpl if="{dataIndex}"&gt;\{{dataIndex}\}&lt;/tpl&gt;</td>'

hschaefer123
30 Jul 2012, 1:15 AM
I am currently migrating my Ext 3.x portal solution to Ext 4.1.x.

Based on Loaines work and my former addons i figured out some issues and fixed them for my needs!

1) wrong use of renderer
i replaced "column.renderer.call" by
column.renderer(value, meta, item, row, col, grid.store, grid.view)
If you still will use column.renderer.call, first param (scope) needs to be column instead of this.

The issue is on using locales different from english and the columns renderer needs corresponding scope. If not some column renderer (datecolumn) will not format dates overwriten in locale based files!

2) wrong asociation of convertedData
array was indexed by dataIndex, but this restriction allows only single use of dataIndex for columns, means you can't use dataindex inside templatecolumn, because value will be overwritten (for example tpl columns with icons, all column using the same dataindex will be shown icon value). Last column wins!
For this reason i index columns by column.id to allow multiple use of corresponding values.

3) adding support for column align (left|center|right)
Added basic formatting support. Currently only column alignment that is used by numbercolmns (align: right).

4) new feature print preview window
During migration i found out that i must not upgrade my iframe panel, because default ux iframe panel fullfills my needs. At this point i thought why not to use iframe panel for printing instead of open new window (it will be quite more comfortable) and so the new print preview window found his way into gridprinter (inspired by loaines print buttons).

37596

Here is the source!
I left the changes inside as comments to see what i have changed.
Also added requires for iframe panel.

Update: updated version and example can be found at
Source: https://github.com/hschaefer123/uops-ext
(https://github.com/hschaefer123/uops-ext)
Update2: online demo available
Demo: http://jsfiddle.net/hschaefer123/NHfsN/
(currently print stylesheet does not work on jsfiddle, but feature itself is ok!)



/**
* @class Ext.ux.grid.Printer
* @author Ed Spencer (edward@domine.co.uk)
* Helper class to easily print the contents of a grid. Will open a new window with a table where the first row
* contains the headings from your column model, and with a row for each item in your grid's store. When formatted
* with appropriate CSS it should look very similar to a default grid. If renderers are specified in your column
* model, they will be used in creating the table. Override headerTpl and bodyTpl to change how the markup is generated
*
* Usage:
*
* 1 - Add Ext.Require Before the Grid code
* Ext.require([
* 'Ext.ux.grid.GridPrinter',
* ]);
*
* 2 - Declare the Grid
* var grid = Ext.create('Ext.grid.Panel', {
* columns: //some column model,
* store : //some store
* });
*
* 3 - Print!
* Ext.ux.grid.Printer.mainTitle = 'Your Title here'; //optional
* Ext.ux.grid.Printer.print(grid);
*
* Original url: http://edspencer.net/2009/07/printing-grids-with-ext-js.html
*
* Modified by Loiane Groner (me@loiane.com) - September 2011 - Ported to Ext JS 4
* http://loianegroner.com (English)
* http://loiane.com (Portuguese)
*
* Modified by Paulo Goncalves - March 2012
*
* Modified by Beto Lima - March 2012
*
* Modified by Beto Lima - April 2012
*
* Modified by Paulo Goncalves - May 2012
*
* Modified by Nielsen Teixeira - 2012-05-02
*
* Modified by Joshua Bradley - 2012-06-01
*
* Modified by Holger Schäfer - 2012-07-30
*
* FORUM: http://www.sencha.com/forum/showthread.php?146348-ExtJS-4-Grid-Printer-Plugin
* GIT: https://github.com/loiane/extjs4-ux-gridprinter
*/
Ext.define("Ext.ux.grid.Printer", {
requires: [
'Ext.XTemplate',
'Ext.ux.IFrame'
],
statics: {
/**
* Prints the passed grid. Reflects on the grid's column model to build a table, and fills it using the store
* @param {Ext.grid.Panel} grid The grid to print
*/
print: function(grid, targetEl) {
if (!targetEl) targetEl = Ext.getBody();

//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 = [];
//account for grouped columns
Ext.each(grid.columns, function(c) {
if (c.items.length > 0) {
columns = columns.concat(c.items.items);
} else {
columns.push(c);
}
});

//build a useable array of store data for the XTemplate
var data = [];
var emptyText = this.text;
grid.store.data.each(function(item, row) {
var convertedData = {};
//apply renderers from column model
for (var key in item.data) {
var value = item.data[key];

Ext.each(columns, function(column, col) {
if (column && column.dataIndex == key) {
/*
* TODO: add the meta to template
*/
var meta = {item: '', tdAttr: '', tdCls: '', style: ''};
value = column.renderer
//? column.renderer.call(column, value, meta, item, row, col, grid.store, grid.view)
? column.renderer(value, meta, item, row, col, grid.store, grid.view)
: value;

// add style info
// TODO: find out how to use metahandling via template (above handling via renderer does not work)
var align = column.align; // [left|center|right]
var style = '';
if (align != 'left') {
style += 'text-align:' + align + ';';
value = '<div style="' + style + '">' + value + '</div>';
}
convertedData[column.id] = (Ext.isEmpty(value))
? emptyText : value;
}
}, this);
}
data.push(convertedData);
});

//remove columns that do not contains dataIndex or dataIndex is empty. for example: columns filter or columns button
var clearColumns = [];
Ext.each(columns, function(column) {
if (column && !Ext.isEmpty(column.dataIndex) && !column.hidden) {
clearColumns.push(column);
}
});
columns = clearColumns;

//get Styles file relative location, if not supplied
if (this.stylesheetPath === null) {
var scriptPath = Ext.Loader.getPath('Ext.ux.grid.Printer'); // library/extjs/src/ux/grid/Printer.js
this.stylesheetPath = scriptPath.substring(0, scriptPath.indexOf('Printer.js')) + 'gridPrinterCss/print.css';
}

//use the headerTpl and bodyTpl markups to create the main XTemplate below
var headings = Ext.create('Ext.XTemplate', this.headerTpl).apply(columns);
var body = Ext.create('Ext.XTemplate', this.bodyTpl).apply(columns);
var pluginsBody = '',
pluginsBodyMarkup = [];

//add relevant plugins
Ext.each(grid.plugins, function(p) {
if (p.ptype == 'rowexpander') {
pluginsBody += p.rowBodyTpl.join('');
}
});

if (pluginsBody != '') {
pluginsBodyMarkup = [
'<tr class="{[xindex % 2 === 0 ? "even" : "odd"]}"><td colspan="' + columns.length + '">',
pluginsBody,
'</td></tr>',
];
}

//Here because inline styles using CSS, the browser did not show the correct formatting of the data the first time that loaded
var htmlMarkup = [
'<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">',
'<html class="' + Ext.baseCSSPrefix + 'ux-grid-printer">',
'<head>',
'<meta content="text/html; charset=UTF-8" http-equiv="Content-Type" />',
'<link href="' + this.stylesheetPath + '" rel="stylesheet" type="text/css" />',
'<title>' + grid.title + '</title>',
'</head>',
'<body class="' + Ext.baseCSSPrefix + 'ux-grid-printer-body">',
/*
'<div class="' + Ext.baseCSSPrefix + 'ux-grid-printer-noprint ' + Ext.baseCSSPrefix + 'ux-grid-printer-links">',
'<a class="' + Ext.baseCSSPrefix + 'ux-grid-printer-linkprint" href="javascript:void(0);" onclick="window.print();">' + this.printLinkText + '</a>',
'<a class="' + Ext.baseCSSPrefix + 'ux-grid-printer-linkclose" href="javascript:void(0);" onclick="window.close();">' + this.closeLinkText + '</a>',
'</div>',
*/
'<h1>' + this.mainTitle + '</h1>',
'<table>',
'<thead>',
'<tr>',
headings,
'</tr>',
'</thead>',
'<tbody>',
'<tpl for=".">',
'<tr class="{[xindex % 2 === 0 ? "even" : "odd"]}">',
body,
'</tr>',
pluginsBodyMarkup.join(''),
'</tpl>',
'</tbody>',
'</table>',
'</body>',
'</html>'
];
var html = Ext.create('Ext.XTemplate', htmlMarkup).apply(data);
// produce inline src content from html
// var src = 'data:text/html;charset=utf-8,' + escape(html);

var printWindow = Ext.createWidget('window', {
requireIcons: ['cross', 'printer'],
title: this.printPreviewText + ': ' + grid.title,
iconCls: 'icon-printer',
width: 640,
height: 480,
layout: 'fit',
animateTarget: targetEl,
resizable: false,
maximizable: true,
items: [{
xtype: 'uxiframe',
itemId: 'iframe'
}],
dockedItems: [
{
xtype: 'toolbar',
dock: 'bottom',
ui: 'footer',
layout: {
pack: 'end',
type: 'hbox'
},
items: [
{
xtype: 'button',
text: this.printLinkText,
iconCls: 'icon-printer',
handler: function(btn, e) {
iframe.getWin().print();
},
scope: this
},
{
xtype: 'button',
text: this.closeLinkText,
iconCls: 'icon-cross',
handler: function(btn, e) {
this.up('window').close();
}
}
]
}
]
});
var iframe = printWindow.down('#iframe');
printWindow.show(targetEl, function() {
var doc = iframe.getDoc();
doc.open();
doc.write(html);
doc.close();
}, this);

/*
//open up a new printing window, write to it, print it and close
var win = window.open('', 'printgrid');
// fix safari
//var win=window.open('about:blank','printgrid');

//document must be open and closed
win.document.open();
win.document.write(html);
win.document.close();
*/

//An attempt to correct the print command to the IE browser
if (this.printAutomatically){
if (Ext.isIE){
window.print();
} else {
win.print();
}
}

//Another way to set the closing of the main
if (this.closeAutomaticallyAfterPrint){
if(Ext.isIE){
window.close();
} else {
win.close();
}
}
},

/**
* @property stylesheetPath
* @type String
* The path at which the print stylesheet can be found (defaults to 'ux/grid/gridPrinterCss/print.css')
*/
stylesheetPath: null,

/**
* @property printAutomatically
* @type Boolean
* True to open the print dialog automatically and close the window after printing. False to simply open the print version
* of the grid (defaults to false)
*/
printAutomatically: false,

/**
* @property closeAutomaticallyAfterPrint
* @type Boolean
* True to close the window automatically after printing.
* (defaults to false)
*/
closeAutomaticallyAfterPrint: false,


/**
* @cfg {String} text
* The header text to be used as innerHTML (html tags are accepted) to display in the Grid.
* **Note**: to have a clickable header with no text displayed you can use the default of ` ` aka `&nbsp;`.
*/
text: ' ',

/**
* @property mainTitle
* @type String
* Title to be used on top of the table
* (defaults to empty)
*/
mainTitle: '',

/**
* Text show as window title
* @type String
*/
printPreviewText: 'Printpreview',

/**
* Text show on print link
* @type String
*/
printLinkText: 'Print',

/**
* Text show on close link
* @type String
*/
closeLinkText: 'Close',

/**
* @property headerTpl
* @type {Object/Array} values
* The markup used to create the headings row. By default this just uses <th> elements, override to provide your own
*/
headerTpl: [
'<tpl for=".">',
'<th>{text}</th>',
'</tpl>',
],

/**
* @property bodyTpl
* @type {Object/Array} values
* The XTemplate used to create each row. This is used inside the 'print' function to build another XTemplate, to which the data
* are then applied (see the escaped dataIndex attribute here - this ends up as "{dataIndex}")
*/
bodyTpl: [
'<tpl for=".">',
//'<td>\{{dataIndex}\}</td>',
'<td>\{{id}\}</td>',
'</tpl>',
]
}
});

dumidu
7 Aug 2012, 11:05 PM
Great plugin

happy to know how to add row numbers to the printed grid

caballero
22 Aug 2012, 1:49 PM
Here is the source!
I left the changes inside as comments to see what i have changed.
Also added requires for iframe panel.

Update: updated version and example can be found at
https://github.com/hschaefer123/uops-ext



Hey hschaefer123 (http://www.sencha.com/forum/member.php?39068-hschaefer123),
Big thanks for what you've done here.
Providing the code with example html in your git repository is a beautiful thing.
Love the improvements.

caballero
28 Aug 2012, 12:23 PM
I am currently migrating my Ext 3.x portal solution to Ext 4.1.x.

4) new feature print preview window
During migration i found out that i must not upgrade my iframe panel, because default ux iframe panel fullfills my needs. At this point i thought why not to use iframe panel for printing instead of open new window (it will be quite more comfortable) and so the new print preview window found his way into gridprinter (inspired by loaines print buttons).

37596

Here is the source!
I left the changes inside as comments to see what i have changed.
Also added requires for iframe panel.


@hschaefer123 (http://www.sencha.com/forum/member.php?39068-hschaefer123)
It was reported to me that the new print preview fails in IE. (IE8 & IE9)
I've verified that the supplied example fails in the same manner.
What happens is the entire page as shown in the image above gets printed, not just the frame as it does in Safari and Firefox.
I've looked through the IE config and can see nothing that would change this behavior.

I will keep poking around, but would appreciate some guidance if you have some thoughts.

caballero
28 Aug 2012, 4:58 PM
@hschaefer123 (http://www.sencha.com/forum/member.php?39068-hschaefer123)
It was reported to me that the new print preview fails in IE. (IE8 & IE9)
I've verified that the supplied example fails in the same manner.
What happens is the entire page as shown in the image above gets printed, not just the frame as it does in Safari and Firefox.
I've looked through the IE config and can see nothing that would change this behavior.

I will keep poking around, but would appreciate some guidance if you have some thoughts.

OK, I think I have a simple solution.

insert his line:
iframe.getWin().focus();

before this line:
iframe.getWin().print();

My tests show this solve my IE issues.

dolaemoney
28 Aug 2012, 5:12 PM
Have not used this yet
Simply thank for author's effort:)

hschaefer123
29 Aug 2012, 1:09 AM
Hi Guys,
just solving this issue by myself to see, that caballero has fixed it before the same way.

I have updated the repository with the new fix used for all browsers because the same solution also work on chrome and firefox.

I also added jsfiddle demo of grid print to see it in action (currently i could not get css stylesheet running hosted on githib for wrong mime header, but functionally it works!) .

For Demo link see original post above.

Cheers Holger

mvorpagel
11 Sep 2012, 7:49 AM
Hi Loiane,
It doesn't look like source code is available on github anymore? Has it been officially added to ExtJS release, and maybe I'm just missing it?

Thanks!

loiane
11 Sep 2012, 8:28 AM
Hi Loiane,
It doesn't look like source code is available on github anymore? Has it been officially added to ExtJS release, and maybe I'm just missing it?

Thanks!

Hi, the code is still on github.

https://github.com/loiane/extjs4-ux-gridprinter

jonasby
18 Sep 2012, 5:00 AM
I noticed your example page uses 4.0.2 which doesn't have Ext.String.createVarName

You might want to use 4.1.1

Great plugin, thanks for keeping it updated!

loiane
24 Sep 2012, 10:53 AM
As requested, added support to Grid Row Numbered plugin.

https://github.com/loiane/extjs4-ux-gridprinter

Will continue working to improve the plugin!

blackpig
26 Sep 2012, 3:23 AM
Hi,
I've tried to use your plugin in my project and works fine (thanks), but i needed also other feature than printing only list. I'm musing plugins like groupping, summaries, etc. Sometimes client need to print what he can see on the screen - ex. collapsed groups with summaries etc... I found a simple solution for this problem, by cutting table that is scrolled in the grid, using extjs-all.css and optional own css... I've added my method to your class and here is a code:

printGroups:function (grid){
var html = jQuery('#'+grid.id+' .x-grid-table:first').html();
html =
'<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">'+
'<html>'+
'<head>'+
'<meta content="text/html; charset=UTF-8" http-equiv="Content-Type" />'+
'<link href="./libraries/ExtJS-4.0.7/resources/css/ext-all.css" rel="stylesheet" type="text/css" />'+
'<link href="' + this.stylesheetPathGroups + '" rel="stylesheet" type="text/css" />'+
'<title>' + grid.title + '</title>'+
'</head>'+
'<body ><table>'+
html+
'</table></body>'+
'</html>';
var win = window.open('', 'printgridGroups');
win.document.open();
win.document.write(html);
win.document.close();
if (this.printAutomatically){
win.print();
}
},
Using jQuery here, but may be replaced with ExtJS.
Example image:

38938

You can also get column headers if needed and insert in generated template


var headers = jQuery('#'+grid.id+' .x-grid-header-ct').html();

loiane
26 Sep 2012, 10:00 AM
Thanks for the contribution blackpig!

You you want to you can make a pull request into the repository and add your credits for this code! This way everyone else will be able to use your code as well! :)

Felipe-BR
4 Oct 2012, 6:21 AM
Olá a todos! Hey everyone!

I found a bug when the columns name are numbers. Ie.:
Encontrei um bug quando o nome da coluna são números. Por exemplo:

39139

Printing is not rendered. Can you help me?
A impressão não é renderizada. Vocês podem me ajudar?


"metaData": {
"root": "empresas",
"fields": [{
"type": "string",
"name": "ano2008",
"mapping": "indicadores.ano2008.quantidadeProcesso",
"defaultValue": "undefined"
}, {
"type": "string",
"name": "ano2009",
"mapping": "indicadores.ano2009.quantidadeProcesso",
"defaultValue": "undefined"
}, {
"type": "string",
"name": "ano2010",
"mapping": "indicadores.ano2010.quantidadeProcesso",
"defaultValue": "undefined"
}, {
"type": "string",
"name": "ano2011",
"mapping": "indicadores.ano2011.quantidadeProcesso",
"defaultValue": "undefined"
}, {
"type": "string",
"name": "ano2012",
"mapping": "indicadores.ano2012.quantidadeProcesso",
"defaultValue": "undefined"
}, {
"type": "int",
"name": "soma"
}],
"colunas": [{
"width": 80,
"renderer": Ext.util.Format.numberRenderer('0,000'),
"align": "right",
"cls": "coluna-grid-center",
"header": "2008",
"sortable": true,
"id": "id2008",
"dataIndex": "ano2008"
}, {
"width": 80,
"renderer": Ext.util.Format.numberRenderer('0,000'),
"align": "right",
"cls": "coluna-grid-center",
"header": "2009",
"sortable": true,
"id": "id2009",
"dataIndex": "ano2009"
}, {
"width": 80,
"renderer": Ext.util.Format.numberRenderer('0,000'),
"align": "right",
"cls": "coluna-grid-center",
"header": "2010",
"sortable": true,
"id": "id2010",
"dataIndex": "ano2010"
}, {
"width": 80,
"renderer": Ext.util.Format.numberRenderer('0,000'),
"align": "right",
"cls": "coluna-grid-center",
"header": "2011",
"sortable": true,
"id": "id2011",
"dataIndex": "ano2011"
}, {
"width": 80,
"renderer": Ext.util.Format.numberRenderer('0,000'),
"align": "right",
"cls": "coluna-grid-center",
"header": "2012",
"sortable": true,
"id": "id2012",
"dataIndex": "ano2012"
}, {
"width": 74,
"renderer": Ext.util.Format.numberRenderer('0,000'),
"align": "right",
"cls": "coluna-grid-center",
"header": "Soma",
"sortable": true,
"id": "idsoma",
"dataIndex": "soma"
}]
}

iplanit
8 Oct 2012, 2:03 AM
I put the plugin into a Grid in my Sencha Architect project and I get the following error:



Uncaught TypeError: Cannot read property 'columns' of undefined


The grid has headers, but otherwise is a regular Grid.



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 = [];
//account for grouped columns
Ext.each(grid.columns, function(c) { <-- error
if(c.items.length > 0) {
columns = columns.concat(c.items.items);
} else {
columns.push(c);
}
});

iplanit
8 Oct 2012, 2:07 AM
It is working, I was using a wrong reference (Ext.getCmp).

Fixing it makes the printing table renders.

Thanks.

loiane
8 Oct 2012, 1:12 PM
Olá a todos! Hey everyone!

I found a bug when the columns name are numbers. Ie.:
Encontrei um bug quando o nome da coluna são números. Por exemplo:



Thanks for reporting the bug. Will try to reproduce and fix it.

loiane
8 Oct 2012, 2:16 PM
Added Sencha Architect example - in case anyone wants to use it with SA2:

https://github.com/loiane/extjs4-ux-gridprinter

iplanit
9 Oct 2012, 12:14 AM
Thanks

Added Sencha Architect example - in case anyone wants to use it with SA2:

https://github.com/loiane/extjs4-ux-gridprinter

Felipe-BR
15 Oct 2012, 5:37 AM
Loiane! Thanks!

drindal
15 Oct 2012, 6:49 AM
Hi,
how can I print a template column?

my grid column code is:

{
xtype:'templatecolumn',
tpl:'{NETPR} {WAERS}',
dataIndex: 'NETPR',
text: 'Netto'
},

i have tried to change the code as descriped earlier in this thread

} else if (column && column.xtype === 'templatecolumn') {
convertedData[column.dataIndex] = column.tpl ? column.tpl.apply(item.data) : value;
}

but it is not working.. it's only showing an empty Netto Column

I hope someone can help me.
Thanks.

Felipe-BR
15 Oct 2012, 12:53 PM
Loiane! About that bug, i found the error and i fix it.


var dataPrinter = [];
grid.store.data.each(function(item, row) {
var convertedData = {};
// apply renderers from column model
for (var key in item.data) {
var value = item.data[key];
Ext.each(columns, function(column, col) {
if (column.dataIndex == key) {
/*
* TODO: add the meta to template
*/
var meta = {
item : '',
tdAttr : '',
style : ''
};
value = column.renderer
? column.renderer.call(grid, value,
meta, item, row, col,
grid.store, grid.view)
: value;
varName = Ext.String.createVarName(column.dataIndex);
convertedData[varName] = value;
}
}, this);
}
dataPrinter.push(convertedData);
});



bodyTpl : ['<tpl for=".">',
'<td>\{{[Ext.String.createVarName(values.dataIndex)]}\}</td>',
'</tpl>']
}

grpbhb
16 Oct 2012, 10:21 AM
With RowExpander of Extjs 4.1.2 doesn't work,


Ext.each(grid.plugins, function(p) {
if (p.ptype == 'rowexpander') {
pluginsBody += p.rowBodyTpl.join(''); //In 4.1.2 rowBodyTpl is a XTemplate object
}
});


1- How obtain the compiled template with the data of each record?
2- I want to show only the expanded rows, not all rows.
Thanks!

loiane
17 Oct 2012, 9:45 AM
Loiane! About that bug, i found the error and i fix it.


Thanks Felipe, already committed the fix on github.

loiane
17 Oct 2012, 4:47 PM
Hi,
how can I print a template column?

my grid column code is:

{
xtype:'templatecolumn',
tpl:'{NETPR} {WAERS}',
dataIndex: 'NETPR',
text: 'Netto'
},

i have tried to change the code as descriped earlier in this thread

} else if (column && column.xtype === 'templatecolumn') {
convertedData[column.dataIndex] = column.tpl ? column.tpl.apply(item.data) : value;
}

but it is not working.. it's only showing an empty Netto Column

I hope someone can help me.
Thanks.

Fixed.
You can get the new version from github and use.
Template columns are now supported by the plugin.

loiane
17 Oct 2012, 4:51 PM
With RowExpander of Extjs 4.1.2 doesn't work,


Ext.each(grid.plugins, function(p) {
if (p.ptype == 'rowexpander') {
pluginsBody += p.rowBodyTpl.join(''); //In 4.1.2 rowBodyTpl is a XTemplate object
}
});


1- How obtain the compiled template with the data of each record?
2- I want to show only the expanded rows, not all rows.
Thanks!

Sorry. I don't have access to 4.1.2 yet. I only use open source version - educational purposes.

grpbhb
18 Oct 2012, 3:37 AM
Ok, but the problem exists!.
"pluginsBody += p.rowBodyTpl.join('');" only appends tpl, How obtain the compiled template with the data of each record?
I want to show only the expanded rows.
Thanks!

CE_REAL
19 Oct 2012, 7:03 AM
Hey I'm using the grid printer plugin and it works great. But now I want to display the header every 30 or so rows. I'm not really that advanced with ExtJS yet so I hope someone can help me breaking up the data to add more than one header.

Thanks in advance.

Edit:

I found a solution for my problem. I added thead and tbody to my output HTML:



'<table>',
'<thead>',
headings,
'</thead>',
'<tbody>',
'<tpl for=".">',
body,
'</tpl>',
'</tbody>',
'</table>',


And then added thead styling to my stylesheet:


thead { display: table-header-group; }

Which then results in displaying the header on every page that is printed.

drindal
22 Oct 2012, 3:10 AM
Fixed.
You can get the new version from github and use.
Template columns are now supported by the plugin.

thank you! works now.

CE_REAL
22 Oct 2012, 7:18 AM
I've got a new challenge, I see the Grid Printer working when a gird is created. But I'm using the http://dev.sencha.com/deploy/ext-4.0.0/examples/writer/writer.html example, which creates no grid but only defines it and creates it using the following:



var main = Ext.create('Ext.container.Container', {
renderTo: Ext.Element.get('invoice-summary'),
layout: 'fit',
autoHeight: true,
items: [{
itemId: 'grid',
xtype: 'writergrid',
flex: 1,
store: store
}]
});


So when I try using the gridprinter it sends an empty grid, which shows up in Firebug as h() which has no store to access by using grid.store. So I get errors and have no data to show in the printview.

loiane
22 Oct 2012, 12:30 PM
I've got a new challenge, I see the Grid Printer working when a gird is created. But I'm using the http://dev.sencha.com/deploy/ext-4.0.0/examples/writer/writer.html example, which creates no grid but only defines it and creates it using the following:



var main = Ext.create('Ext.container.Container', {
renderTo: Ext.Element.get('invoice-summary'),
layout: 'fit',
autoHeight: true,
items: [{
itemId: 'grid',
xtype: 'writergrid',
flex: 1,
store: store
}]
});


So when I try using the gridprinter it sends an empty grid, which shows up in Firebug as h() which has no store to access by using grid.store. So I get errors and have no data to show in the printview.

You need to pass an instance of a GridPanel to the plugin.
In your case, you can get the grid instance using the following code - this will be your grid variable:

Ext.ComponentQuery.query('writergrid[itemId=grid]')[0]

CE_REAL
23 Oct 2012, 11:46 PM
You need to pass an instance of a GridPanel to the plugin.
In your case, you can get the grid instance using the following code - this will be your grid variable:

Ext.ComponentQuery.query('writergrid[itemId=grid]')[0]

I used your solution and I got it to work with the toolbar printbutton. Now I'm being a bit demanding with my usage of the gridprinter.

I'll explain my whole situation a bit better:

First of all I've got one page with two containers:



var total = Ext.create('Ext.container.Container', {
renderTo: Ext.Element.get('invoice-summary-total'),
layout: 'fit',
autoHeight: true,
items: [{
itemId: 'grid',
xtype: 'writergrid',
flex: 1,
store: total_store
}]
});


var main = Ext.create('Ext.container.Container', {
renderTo: Ext.Element.get('invoice-summary'),
layout: 'fit',
autoHeight: true,
items: [{
itemId: 'grid',
xtype: 'writergrid',
flex: 1,
store: store
}]
});


Both are using the same defined grid:


var grid = Ext.define('Writer.Grid', {
extend: 'Ext.grid.Panel',
alias: 'widget.writergrid',


requires: [
'Ext.grid.plugin.CellEditing',
'Ext.form.field.Text',
'Ext.toolbar.TextItem',
'Ext.ux.grid.Printer'
],


initComponent: function(){


this.editing = Ext.create('Ext.grid.plugin.RowEditing', {
clicksToMoveEditor: 1,
autoCancel: false
});


Ext.apply(this, {
title: 'Invoice summary' + ' [<?php echo $customer_information['id'] .' ' .$customer_information['name'] ?>]',
iconCls: 'icon-grid',
frame: true,
plugins: [this.editing],
columns: [{
text: '<?php echo __('Invoice number') ?>',
width: 80,
sortable: true,
dataIndex: 'number',
renderer: function(value, metaData, record, rowIndex, colIndex, store) {
var linkReturn = '';
var customerId = '<?php echo $customer_information['id'] ?>';
if (!isNaN(record.data.number) && record.data.number != '') {
linkReturn = '<a href="' + url + "/agent/invoicePaymentSummary/" + '<?php echo $customer_information['id'] ?>'+ "/" + record.data.number +'">'+ record.data.number +'</a>';
} else {
linkReturn = record.data.number;
}
return linkReturn;
}
}, {
header: '<?php echo __('Date') ?>',
width: 70,
sortable: true,
dataIndex: 'date',
renderer: Ext.util.Format.dateRenderer('d-m-Y'),
}, {
header: '<?php echo __('Due date') ?>',
width: 70,
sortable: true,
dataIndex: 'due_date',
renderer: Ext.util.Format.dateRenderer('d-m-Y'),
renderer: function(value, metaData, record, rowIndex, colIndex, store) {
var returnValue = Ext.Date.format(value, "d-m-Y");
var dueDate = value;
var today = new Date();
if(dueDate < today && record.data.overdue_days > 0) {
returnValue = '<p class="red">'+ returnValue +'</p>';
}
return returnValue;
}
}, {
header: '<?php echo __('Invoice amount') ?>',
width: 90,
sortable: true,
dataIndex: 'invoice_amount',
align: 'right',
renderer: money
}, {
header: '<?php echo __('Paid') ?>',
width: 90,
sortable: true,
dataIndex: 'paid',
align: 'right',
renderer: money
}, {
header: '<?php echo __('Remaining') ?>',
width: 90,
sortable: true,
dataIndex: 'remaining',
align: 'right',
renderer: money
}, {
header: '<?php echo __('Currency') ?>',
width: 60,
sortable: true,
dataIndex: 'currency'
}, {
header: '<?php echo __('Draft') ?>',
width: 40,
sortable: true,
dataIndex: 'draft',
align: 'right',
renderer: redClass
}, {
header: '<?php echo __('Overdue days') ?>',
width: 80,
sortable: true,
dataIndex:"overdue_days",
align: 'right',
renderer: redOverdueDaysClass
}, {
xtype: 'numbercolumn',
header: '<?php echo __('Pay-week') ?>',
width: 80,
sortable: true,
dataIndex:"pay_week",
format: '0',
field: {
xtype: 'numberfield',
allowBlank: false,
minValue: period,
regex: /^[0-9]{4}([0][1-9]|[1-4][0-9]|[5][0-2])$/i,
maskRe: /^[0-9]{4}([0][1-9]|[1-4][0-9]|[5][0-2])$/i,
regexText: 'Format YYYYWW (Min. YYYY01 - Max. YYYY52)'
},
align: 'right',
vtype: 'payweek',
renderer: redPayWeekField
}, {
header: '<?php echo __('Comment') ?>',
width: 220,
sortable: true,
dataIndex:"comment",
field: {
type: 'textfield',
maxLength: 30,
emptyText: ''
},
renderer: redCommentField
}, {
header: '<?php echo __('Send address') ?>',
width: 200,
sortable: true,
dataIndex:"send_address"
}, {
header: '<?php echo __('PDF') ?>',
width: 40,
sortable: true,
dataIndex:"pdf",
renderer: function(value, metaData, record, rowIndex, colIndex, store) {
var pdfReturn = '';
var customerId = '<?php echo $customer_information['id'] ?>';
if (!isNaN(record.data.number) && record.data.number != '')
pdfReturn = '<a href="' + url + '/agent/invoiceSummary/viewInvoice/'+ record.data.number +'/'+ customerId +'" target="_blank">'+ '<img src="/images/icons/pdf_icon.gif"></a>';
return pdfReturn;
}
}],
tbar: [{
text: 'Print',
iconCls: 'icon-print',
handler : function(){
Ext.ux.grid.Printer.printAutomatically = true;
Ext.ux.grid.Printer.print(Ext.ComponentQuery.query('writergrid[itemId=grid]')[1]);
}
}]
});
this.callParent();

onSync: function(){
this.store.sync();
}
});


Now I'd like to print the first grid and print the second grid with both their own print button in the toolbar.

I'm thinking of maybe creating two different toolbars and using them in the container, but I don't really know how to add them to the container.

And the second thing I like, is using my own print button outside of the grid like:


<div id="print"><button id="printPage" onclick="Ext.ux.GridPrinter.print(invoiceSummaryGrid)">Print</button></div>


But I can't get my grid object to send to the Ext.ux.GridPrinter.print function. I get the following error:



TypeError: grid.store is undefined
grid.store.data.each(function(item, row)

I hope you can help me with this problem.

Radius-Service
19 Nov 2012, 3:30 AM
Printing GridPanels with GroupingView and GroupSummary plugin

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

But working with Ext 3 only