Archive | JavaScript RSS for this section

Dojo Data Grid – Part 31: Setting Row Styles on Hover, Selection, and Alternate Rows

In this post, I’ll show how change the row color in an XPages Dojo Data Grid based on whether the row is hovered over, selected, or is an odd-numbered row.

Dojo Data Grid Series

Dojo Grids in XPages — All Blog Posts

Row Styling

By default, the grid will provide alternate row coloring and different styles when you select or hover over a row. This image shows all three of those styles in effect.
Grid 30A

However, as soon as you add any code into the event handler, you lose the hover, selected, and alternate row styles.

The client-side onStyleRow allows us to re-apply this styling or change it. The event executes as each row is drawn in the grid, which is the timing we need in order to dynamically set the row styling. See my previous post on the onStyleRow event for more information.

Restoring the Default Styles

To restore the default styles, you can use the same class names that the grid uses to apply the styles.

  • Alternate Rows – dojoxGridRowOdd
  • Row Hover – dojoxGridRowOver
  • Row Selection – dojoxGridRowSelected
// This event automatically receives an object with information about the current row. It's not named, so we refer to it by arguments[0]
var row = arguments[0];

if (row.over) {
  row.customClasses = 'dojoxGridRowOver';
} else if (row.selected) {
  row.customClasses = 'dojoxGridRowSelected';
} else if (row.odd) {
  row.customClasses = 'dojoxGridRowOdd';
}

Customizing the Styles

Now that you understand how this works, it is just as easy to change the styles completely in these three cases.

Just define classes in CSS and include the style sheet on the page and you use the same technique to append classes to rows as needed.

In this hideous example, alternate rows are set to blue, selected rows are set to yellow, and the hovered row is set to red.

Grid 31

var row = arguments[0];

if (row.over) {
  row.customClasses = 'redRow';
} else if (row.selected) {
  row.customClasses = 'yellowRow';
} else if (row.odd) {
  row.customClasses = 'blueRow';
}
Advertisements

Dojo Data Grid – Part 30: The onStyleRow Event

In this post, I’ll dig into the onStyleRow event of the XPages Dojo Data Grid in order to show how it can be used to modify the display of grid rows. This will lay the foundation for the next few posts.

Dojo Data Grid Series

Dojo Grids in XPages — All Blog Posts

The onStyleRow Event

The onStyleRow event runs on each row in the grid as it is rendered. The event handler automatically receives one argument that has a number of properties that can be used to conditionally customize the display of the row.

By default, the grid will provide alternate row coloring and different styles when you select or hover over a row. This image shows all three of those styles in effect.
Grid 30A

However, as soon as you add any code into the event handler, you lose the hover, selected, and alternate row styles. (In this case, I added a single comment to the event handler and it was still enough to cause other styles to be dropped.)
Grid 30B

onStyleRow Argument Properties

The onStyleRow event automatically receives an object with information about the current row. It’s not a named argument, so we refer to it by arguments[0]. The properties of the row object are as follows:

  • index (row index)
  • node (DOM node)
  • odd (boolean — whether the row is an odd-numbered row)
  • selected (boolean — whether the row is currently selected)
  • over (boolean — whether the row is currently hovered over)
  • customStyles (used to add style information to the row)
  • customClasses (used to add classes to the row)

The index property is the 0-based number of the row in the grid.

odd, selected, and over are boolean properties that are handy for changing styles for alternate rows and whether the row is selected or hovered over.

The customStyles property is used to add custom style information to the row. The customClasses property is used to add additional classes to the grid row.

The node provides a handle to the DOM node of the grid row.

Here’s an example of what it returns:

</pre>
<table class="dojoxGridRowTable" role="presentation" border="0" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td class="dojoxGridCell " style="width: 6em;" tabindex="-1" role="gridcell" colspan="1">...</td>
<td class="dojoxGridCell " style="width: 6em;" tabindex="-1" role="gridcell" colspan="1">...</td>
<td class="dojoxGridCell " style="width: 6em;" tabindex="-1" role="gridcell" colspan="1">...</td>
<td class="dojoxGridCell " style="width: 6em;" tabindex="-1" role="gridcell" colspan="1">...</td>
<td class="dojoxGridCell " style="width: 6em;" tabindex="-1" role="gridcell" colspan="1">...</td>
<td class="dojoxGridCell " style="width: 6em;" tabindex="-1" role="gridcell" colspan="1">...</td>
</tr>
</tbody>
</table>
<pre>

There are two interesting things to note. First of all, each row in the grid is actually its own table. Secondly, each cell in the row is initially populated with ‘…’. It then fills in the data from the REST service on a second pass.

This is important to understand — the onStyleRow event will generally run more than once on each row. Essentially, whatever settings are applied in the last pass are the ones that stick.

In my testing, it appears to run between 1 and 3 times on each row. It seems to most commonly run twice — once when it sets up the row and pre-populates every cell with ‘…’ and then a second time when it actually fills in the data. (I tested this by reviewing the full contents of the row node.)

It seems to run 3 times on the first chunk of rows displayed when the grid is first loaded. It only runs once one when the data has already been loaded or if the row is read-protected and thus cannot display any data.

Adding event code

I enter code for the onStyleRow event via the All Properties tab and not directly in the event view. Take a look at this post to see why this works differently.

Grid 30 - A

Up Next

Now that we’ve explored what happens in the event and what’s available to it, the next couple of posts will show how to use the event to provide additional row styling.

The difference between two methods of adding client-side JavaScript event-handling code to an XPages input control

There are two ways to add event handling client-side JavaScript code to an XPages input control. This post shows the difference in what is generated and a use case for when the less-obvious method can be useful.

The Scenario

I recently worked on an application designed for a touch screen interface where there are a lot of data entry fields.

In order to make it easier to use, I want it to automatically select the contents of a field when the field receives focus. This way, the user can easily change the value of a field without having to click into a field, select the contents, then delete the existing value and re-enter a new value.

If the contents can be automatically selected when the user sets the focus on a field, then the user can just start typing and it will replace the value.

It may not sound like much, but this is a significant improvement in usability on a touch screen, without using a mouse.

The JavaScript

This is a simple problem to solve on a standard web page. You can put this code on the onfocus event of a field to automatically select the contents:

this.select();

JavaScript Keyword: this

In JavaScript, the keyword this can be used to refer to the object receiving the event that has triggered the handler code.

This is very handy for getting the value of the current field or taking some other action on the field with a very compact syntax. In my case, I was trying to get a handle on the current field in order to select its contents.

Adding JavaScript via the Events View

The standard way to add client-side JavaScript event code is through the Events view. I went there and added the code to the client-side onfocus event.

JSEventCode_1

Here’s what the XPage source looks like:

<xp:inputText id="inputText1" value="#{document1.Field1}" defaultValue="--">
  <xp:eventHandler event="onfocus" submit="false">
    <xp:this.script><![CDATA[this.select();]]></xp:this.script>
  </xp:eventHandler>
</xp:inputText>

This is the HTML and JavaScript generated when the page is rendered:

...
<input type="text" value="--" id="view:_id1:inputText1" name="view:_id1:inputText1" class="xspInputFieldEditBox">
...
<script type="text/javascript">

function view__id1__id4_clientSide_onfocus(thisEvent) {
alert('Value: ' + this.value);
this.select();
}

XSP.addOnLoad(function() {
XSP.attachEvent("view:_id1:_id4", "view:_id1:inputText1", "onfocus", view__id1__id4_clientSide_onfocus, false, 2);
}); 

</script>

This is how client-side JavaScript is added on the XPage. It creates a function and runs code on page load to attach it to the event. In this case ‘this’ is not attached directly to the field.

When I click on the field (thus setting the focus and triggering the onfocus event), I see an error in firebug.

JSEventCode_1b_FirebugError

Workaround

There are ways to work around this limitation. If you add a unique class to the field or compute the client-side ID with pass-through EL syntax (“#{id:inputText1}”), you can get a handle to the field. But this is a little more effort that shouldn’t be necessary.

Adding JavaScript via the Properties View.

I noticed that there’s another place to add onfocus event code. If you click on the field and open the Properties view rather than the events view, you can go to All Properties > events > onfocus. Click on the icon in that field and you can enter JavaScript code.

JSEventCode_2

Code added this way is clearly managed differently than the standard event code. I noticed that code entered via All Properties doesn’t show up in the Events view and vice versa.

There’s a big difference in the output as well. Rather than the JavaScript function and code to attach it to the event handler, code entered this way is passed directly through to the generated input tag.

<input type="text" value="--" id="view:_id1:inputText2" name="view:_id1:inputText2" class="xspInputFieldEditBox" onfocus="this.select();">

This is exactly what I wanted to begin with!

And it works as expected.

Caveat

Since code entered this way is passed directly through, you cannot set it to execute a partial refresh (or trigger any other server side update directly). However, if you need a quick snippet of code that only needs to work with the client-side DOM, this is an option.

You can, however, still include pass-thru EL statements. You just have to realize that, since it’s putting the code directly into the client-side onfocus event, it will already be surrounded by double-quotes by default, so use single quotes instead and account for that.

Update: Handling this.select() in Chrome

It turns out that this.select() doesn’t work in Chrome. It briefly selects the text but immediately loses the selection.

There are two easy workarounds. (1) You can use the onclick event instead. (Tabbing into the field with the keyboard will automatically select the text anyway, so keyboard access is also covered.) (2) You can add return false; to the onmouseup event to allow it to work as well.

This sample field works in Chrome to select the contents when you click on the field:

<xp:inputText id="inputText1" defaultValue="myDefault"
  onfocus="this.select();" onmouseup="return false;">
</xp:inputText>

XPages Tip: EL Statements Do Not Work in JavaScript Library Functions

You may already be aware that you can use Expression Language (EL) to evaluate information on the server into client-side JavaScript code. However, this does not work in a library function. This post explains how modularize your code and still use EL to read server-side information into client-side JavaScript.

Here’s how it usually plays out:

  1. You realize that you need to access the value of an xp:inputText control in client-side JavaScript and use EL syntax in button code to retrieve that value. It works well.
  2. You decide that you’re going to be a good developer and modularize your code for reuse, so you move it to a script library.
  3. The code fails at the point where it tries to evaluate the EL statement.
  4. <facepalm>
  5. You update the library function to accept values evaluated with EL on the page to make it work properly.

An Example

Here’s a page with an xp:inputText (inputText1) and an xp:button to display the value.

alert('Value: ' + dojo.byId('#{id:inputText1}').value);

Blog_EL_CSJS_1

This works because #{id:inputText1} is evaluated on the server and it returns the actual client-side ID for that element and passes it into the client-side javascript code on the button.

When the page is rendered, it generates this function (and then uses dojo to attach it to the button):

function view__id1__id4_clientSide_onclick(thisEvent) {
  alert('Value: ' + dojo.byId('view:_id1:inputText1').value);
}

Notice that there’s a fully-fleshed out ID where I previously had an EL statement.

If I want to use that code more than once, I’d want to move it to a script library function:

function displayFieldValue() {
  alert('Value: ' + dojo.byId('#{id:inputText1}').value);
}

But when I try it, it doesn’t work. Nothing happens in the UI, but there’s an error that I can see in Firebug:

Blog_EL_CSJS_2

The error says that it couldn’t find the field so I can display the value. This is because EL statements do not evaluate in script library functions. They only evaluate in code that is on the page.

Modularization

There is a middle ground, though. If you have code that you want to re-use, you can still move it to a script library — you just have to evaluate EL statements on the page and pass them into the library function.

In this same example, change the library function as shown:

function displayFieldValue(fieldID) {
  alert('Value: ' + dojo.byId(fieldID).value);
}

Then call it from the button like this:

displayFieldValue('#{id:inputText1}');

And now it works!

Get All Properties of an Object in JavaScript

I often have the need to find all of the properties of an object in order to determine what is available to work with. In this post, I’ll show you a handy function that you can use to provide this information.

As I worked through many of the posts in the Dojo Data Grid series, I was routinely slowed down by the lack of detailed documentation on many of the grid and plugin event properties. This function was very useful in inspecting the properties and giving me ideas for new approaches to try.

Fortunately, JavaScript makes it easy to inspect an object and display all of its properties. This function can be called with an object parameter and it will display a list of properties of the object.

function getAllProperties(obj) {
  var properties = '';
  for (property in obj) {
    properties += '\n' + property;
  }
  alert('Properties of object:' + properties);
}

Dojo Data Grid – Part 18: EnhancedGrid Context Menus

The Menu plugin for the Dojo EnhancedGrid gives you the ability to add context menus to grid headers, rows, cells, and selected regions. In this post, I’ll show how to add the plugin and use it.

Dojo Data Grid Series

This post assumes you already have a Dojo Data Grid control set up to use the Dojo EnhancedGrid, based on the instructions in this post.

Load the Menu Plugin (and more)

The dojox.grid.enhanced.plugins.Menu module must be included on the page, so add it to the page resources. Properties > Resources > Add > Dojo Moduleā€¦

Dojo Grid 18 - 1 - Modules

You also need to include the dijit menu and dijit menu item modules, since they’re required to build the context menus.

In this grid, I’m also including the Printer plugin, so I can trigger printing functions from the context menus.

Add the Plugin to the Grid

The first step made the plugin module available, but you also need to add it to the grid.

Go to the properties of the Dojo Data Grid > Dojo and click the Add button. Add two properties as shown here:

Dojo Grid 18 - 2 - Dojo Properties

This is the first example of including more than one EnhancedGrid plugin.

contextMenus is the name of a JavaScript object I’ve created to build the context menus (shown below).

Note: The row selection property is necessary in order to select rows in the grid.

Creating the Menus

To create the context menus, you create an object that contains properties for all of the context menus to define. You then add menu items to those menus and provide onClick events to take action when a context menu option is selected. Example code is shown below.

Using the Context Menus

Right click on column header
Dojo Grid 18 - 3 - Cell Header Context Menu

Right click on row selector
Dojo Grid 18 - 4 - Row Context Menu

Right click on a cell
Dojo Grid 18 - 5 - Cell Context Menu

Right click on a selected region
Dojo Grid 18 - 6 - Selected Region Context Menu

Context Menu Code

This code builds all four types of context menus and provides several actions:

// Set up the context menu object dijit menus
var contextMenus = {
  headerMenu: new dijit.Menu(),
  rowMenu: new dijit.Menu(),
  cellMenu: new dijit.Menu(),
  selectedRegionMenu: new dijit.Menu()
};

// Header Context Menu 
contextMenus.headerMenu.addChild(new dijit.MenuItem({label: "Print All", onClick:printAll}));
contextMenus.headerMenu.addChild(new dijit.MenuItem({label: "Print Selected", onClick:printSelected}));
contextMenus.headerMenu.addChild(new dijit.MenuItem({label: "Print Custom", onClick:printCustomized}));
contextMenus.headerMenu.startup();

// Row Context Menu
contextMenus.rowMenu.addChild(new dijit.MenuItem({label: "Display Click Location", onClick: rowDisplayClickLocation}));
contextMenus.rowMenu.addChild(new dijit.MenuItem({label: "Preview All", onClick:previewAll}));
contextMenus.rowMenu.addChild(new dijit.MenuItem({label: "Preview Selected", onClick:previewSelected}));
contextMenus.rowMenu.addChild(new dijit.MenuItem({label: "Preview Custom", onClick:previewCustomized}));
contextMenus.rowMenu.startup();

// Cell Context Menu
contextMenus.cellMenu.addChild(new dijit.MenuItem({label: "Display Click Location", onClick:cellDisplayClickLocation}));
contextMenus.cellMenu.addChild(new dijit.MenuItem({label: "Cell Menu Item 1", iconClass:'dijitEditorIcon dijitEditorIconCopy',onClick:function(){alert('copy!')}}));
contextMenus.cellMenu.addChild(new dijit.MenuItem({label: "Cell Menu Item 2", iconClass:'dijitEditorIcon dijitEditorIconPaste', onClick:function(){alert('paste!')}}));
contextMenus.cellMenu.addChild(new dijit.MenuItem({label: "Cell Menu Item 3", iconClass:'dijitEditorIcon dijitEditorIconCut', onClick:function(){alert('cut!')}}));
contextMenus.cellMenu.startup();

// Selected Region Context Menu
contextMenus.selectedRegionMenu.addChild(new dijit.MenuItem({label: "Context Info", onClick:function(){alert('row: ' + rowIndex + '\ncell: ' + cellIndex);}}));
contextMenus.selectedRegionMenu.addChild(new dijit.MenuItem({label: "Alert", onClick:function(){alert('selected region')}}));
contextMenus.selectedRegionMenu.startup();

Note: There are references to print and print preview functions from the Printer plugin for the EnhancedGrid. The code for those functions can be found in this post.

Working with the Click Context

What we’ve seen so far is fine to trigger javascript events, but, commonly, you will want to know the context of the click so you can execute logic targeted to that context.

At least 1 of 4 events is fired on the grid when the user right clicks to bring up a context menu:

  • onRowContextMenu(e)
  • onCellContextMenu(e)
  • onHeaderCellContextMenu(e)
  • onSelectedRegionContextMenu(e)

These event handlers all automatically get a handle to an event object (e) that has context information.

To use them, you need to attach a function to the event. In that function, you can set global JavaScript variables with context information. Then, in your context menu item functions, you can access that context information.

To retrieve and use the location of a context menu click, follow these steps:

1. Define global variables and the event handler function(s) in an Output Script tag or client-side JavaScript library:

var rowIndex;
var cellIndex;
		
// onRowContextMenu Event Handler
// Retrieves the rowIndex and cellIndex and stores them in a global variable for the menu click event handlers to reference
// NOTE: This event fires when clicking on a row selector or any cell in the row
function rowContextMenuEvent (e) {
  rowIndex = e.rowIndex;
  cellIndex = e.cellIndex;
}

// onCellContextMenu Event Handler
// Retrieves the rowIndex and cellIndex and stores them in a global variable for the menu click event handlers to reference
// NOTE: This event fires when clicking on any cell in the row. If an onRowContextMenu event handler is also defined, that will fire before this event handler fires.
function cellContextMenuEvent (e) {
  rowIndex = e.rowIndex;
  cellIndex = e.cellIndex;
}

2. Attach the event handler functions to the grid events on the onClientLoad event of your page. Here are examples of attaching to two of the events:

dojo.connect(dijit.byId("#{id:djxDataGrid1}"), "onRowContextMenu", rowContextMenuEvent);
dojo.connect(dijit.byId("#{id:djxDataGrid1}"), "onCellContextMenu", cellContextMenuEvent);

3. Create one or more menu action functions that refer to the global variables and then work with the context.

// Row context menu function to display the index of the row
function rowDisplayClickLocation () {
  alert('row index: ' + rowIndex + '\ncell index: ' + cellIndex);		
}
		
// Cell context menu function to display the index of the row and cell
function cellDisplayClickLocation () {
  alert('row index: ' + rowIndex + '\ncell index: ' + cellIndex);		
}

When the user right-clicks on a row selector to bring up the row context menu, the onRowContextMenu event function runs first, then the context menu is displayed, then the user selects an option from the context menu.

It is interesting to note that if you have event handlers defined for onRowContextMenu and onCellContextMenu, the onRowContextMenu event handler will run first, then the onCellContextMenu event handler will run second. If all you’re doing is getting the row and cell index where the click happend, you don’t even need the onCellContextMenu event handler.

Properties of the Event Object

Just for kicks, I ran a little script to tell me all of the properties available to that event object that’s provided to the context menu event handlers.

Here’s the list, in case you’d like to dig into any of them further:

rowNode, rowIndex, dispatch, grid, sourceView, cellNode, cellIndex, cell, type, target, currentTarget, eventPhase, bubbles, cancelable, timeStamp, defaultPrevented, stopPropagation, preventDefault, initEvent, stopImmediatePropagation, which, rangeParent, rangeOffset, pageX, pageY, isChar, screenX, screenY, mozMovementX, mozMovementY, clientX, clientY, ctrlKey, shiftKey, altKey, metaKey, button, buttons, relatedTarget, mozPressure, mozInputSource, initMouseEvent, initNSMouseEvent, getModifierState, originalTarget, explicitOriginalTarget, preventBubble, preventCapture, getPreventDefault, isTrusted, view, detail, initUIEvent, layerX, layerY, cancelBubble, NONE, CAPTURING_PHASE, AT_TARGET, BUBBLING_PHASE, MOUSEDOWN, MOUSEUP, MOUSEOVER, MOUSEOUT, MOUSEMOVE, MOUSEDRAG, CLICK, DBLCLICK, KEYDOWN, KEYUP, KEYPRESS, DRAGDROP, FOCUS, BLUR, SELECT, CHANGE, RESET, SUBMIT, SCROLL, LOAD, UNLOAD, XFER_DONE, ABORT, ERROR, LOCATE, MOVE, RESIZE, FORWARD, HELP, BACK, TEXT, ALT_MASK, CONTROL_MASK, SHIFT_MASK, META_MASK, SCROLL_PAGE_UP, SCROLL_PAGE_DOWN, MOZ_SOURCE_UNKNOWN, MOZ_SOURCE_MOUSE, MOZ_SOURCE_PEN, MOZ_SOURCE_ERASER, MOZ_SOURCE_CURSOR, MOZ_SOURCE_TOUCH, MOZ_SOURCE_KEYBOARD

Dojo Data Grid – Part 15: EnhancedGrid Printing

In the last post, we looked at the Dojo EnhancedGrid plugin for filtering. In this post, we’ll look at the EnhancedGrid Printer plugin, which provides the ability to preview and print the grid contents.

Dojo Data Grid Series

Print and Preview Functionality

The Printer plugin comes with three print options and three corresponding preview options:

  • Preview/Print All
  • Preview/Print Selected
  • Preview/Print Custom

Start with a Dojo EnhancedGrid

Before you can use an EnhancedGrid plugin, you need to be set up the Dojo Data Grid control to render as a Dojo EnhancedGrid. Follow the steps in this post to get ready.

1. Load the Printer Plugin

The dojox.grid.enhanced.plugins.Printer module must be included on the page, so add it to the page resources. Properties > Resources > Add > Dojo Module…

DojoDataGrid_15_0a_PluginModule

2. Add the Plugin to the Grid

The first step made the plugin module available, but you also need to add it to the grid.

Go to the properties of the Dojo Data Grid > Dojo and click the Add button. Add the property as shown here:

DojoDataGrid_15_0b_PluginAttribute

3. Add Printing and Preview Functions

Next, you need to add the client-side JavaScript functions that will execute the desired print and preview functionality. You can put them in an Output Script tag or a client-side JavaScript library to make them available on the page.

These functions were taken directly from the plugin documentation and modified slightly to work within XPages.

var gridName = "#{id:djxDataGrid1}";

function printAll(){
  dijit.byId(gridName).printGrid({
    title: "Grid Print - All"
  });
}

function printSelected(){
  dijit.byId(gridName).printSelected({
    title: "Grid Print - Selected"
  });
}

function printCustomized(intStart, intCount){
  dijit.byId(gridName).printGrid({
    title: "Grid Print - Customized",
    fetchArgs: {
      start: intStart,
      count: intCount
    }
  });
}

function preview(str){
  var win = window.open();
  win.document.open();
  win.document.write(str);
  /*Adjust row height/view width for multi-view grid*/
  dijit.byId(gridName).normalizePrintedGrid(win.document);
  win.document.close();
}

function previewAll(){
  dijit.byId(gridName).exportToHTML({
    title: "Grid Print - All"
  }, preview);
}

function previewSelected(){
  preview(dijit.byId(gridName).exportSelectedToHTML({
    title: "Grid Print - Selected"
  }));
}

function previewCustomized(intStart, intCount){
  dijit.byId(gridName).exportToHTML({
    title: "Grid Print - Customized",
    fetchArgs: {
      start: intStart,
      count: intCount
    }
  }, preview);
}

The primary changes I made were setting a variable with the client-side ID of the grid and setting the preview and print custom functions to accept variables, rather than use hard-coded values.

4. Add buttons to call the printing functions

Once the functions are ready, you can add buttons (or images or links) with client-side JavaScript code to call the print and preview functions.

Here is the source for the buttons on my sample page:

<xp:button value="Print All" id="button1">
  <xp:eventHandler event="onclick" submit="false">
    <xp:this.script><![CDATA[printAll()]]></xp:this.script>
  </xp:eventHandler>
</xp:button>
<xp:button value="Print Selected" id="button2">
  <xp:eventHandler event="onclick" submit="false">
    <xp:this.script><![CDATA[printSelected()]]></xp:this.script>
  </xp:eventHandler>
</xp:button>
<xp:button value="Print Customized" id="button3">
  <xp:eventHandler event="onclick" submit="false">
    <xp:this.script><![CDATA[printCustomized(200, 30)]]></xp:this.script>
  </xp:eventHandler>
</xp:button>
<xp:button value="Preview All" id="button4">
  <xp:eventHandler event="onclick" submit="false">
    <xp:this.script><![CDATA[previewAll()]]></xp:this.script>
  </xp:eventHandler>
</xp:button>
<xp:button value="Preview Selected" id="button5">
  <xp:eventHandler event="onclick" submit="false">
    <xp:this.script><![CDATA[previewSelected()]]></xp:this.script>
  </xp:eventHandler>
</xp:button>
<xp:button value="Preview Customized" id="button6">
  <xp:eventHandler event="onclick" submit="false">
    <xp:this.script><![CDATA[previewCustomized(200, 30)]]></xp:this.script>
  </xp:eventHandler>
</xp:button>

Default Browser Print Format

By default, the browser’s Print option prints exactly what you see on the page.
DojoDataGrid_15_1_BrowserPrint

Now, let’s take a look at the output from the Printer plugin.

Preview/Print Selected

With the enhanced grid, you can SHIFT+Click to select a set of rows and you can CTRL+Click to select non-contiguous rows. These options allow you to only print selected rows.
DojoDataGrid_15_2a_SelectRows

DojoDataGrid_15_2b_PreviewSelected

Preview/Print Custom

I think this is the best feature. It will start with the specified row and include the specified number of rows thereafter. I updated the code above to make these dynamic, so your print function can pass in variables for the start row and number of rows.

Preview/Print All

Quite frankly, these options are misleading. In my limited testing, they seem to always only include the first chunk of rows in the grid, no matter how far you have scrolled.

Formatting the Output

You can add a cssFiles property to any of these print functions to apply your own style sheet to format the output.

function printAll(){
    dijit.byId("grid").printGrid({
        title: "Grid - All",
        cssFiles: cssFiles
    });
}