EXTJS in XPages #3 – Creating a basic grid from a Custom Control

In this article I will demonstrate how to create an EXTJS grid representation of a view using a custom control and 3 custom properties. At the end of this article you will be able to drag and drop a custom control onto your XPage, give it the count, the viewName and the name of the placement element and a grid will be created for you without any further coding.

Introduction

In XPages we want to be able to genericize everything down to a re-usable custom control and in this example I will show you how to add a grid to your XPage doing just that. The following XPage source code is all that is needed to create this basic grid capability.

<?xml version="1.0" encoding="UTF-8"?>
<xp:view xmlns:xp="http://www.ibm.com/xsp/core" xmlns:xc="http://www.ibm.com/xsp/custom">

	<xc:ccBasicExtJSGrid countNum="10" putGridHere="gridHere" theViewName="ByName-First5Col" ></xc:ccBasicExtJSGrid>

	<div id="gridHere" class="extjsGrid"></div>

</xp:view>

Demonstration

The EXTJS in XPages demonstration database can be found at http://demo.xomino.com/xomino/extjs.nsf

Download

The sample database that will accompany this series is  available from the menu in the live demo database from this link – http://demo.xomino.com/xomino/Extjs.nsf

The Custom Control

The Custom Control is created with 3 Properties which are populated when it is added to the XPage. You add it to your XPage by dragging and dropping and adding the 3 properties:

xt31

The View

The view ByName-First5Col is a simple view of 5 columns containing a single field in each column but as we will see this control will handle any number of columns.

ext32

The code

The end result is to create the JavaScript necessary to create a Basic grid in the same fashion as I did in the first article. But in this case we are not providing the column names or headers, we are programmatically getting them from the view itself.

The fields are created by going to the view and getting the columns and then of those, the item name (nvc.getItemName())

var fields=[
		#{javascript:
				var view:NotesView = database.getView(compositeData.theViewName)	//get the view
				var msg=[];
				for (var i=1; i<view.getColumnCount()+1; i++){
					var nvc:NotesViewColumn = view.getColumn(i);			//get each view column in turn
					msg.push('\''+nvc.getItemName()+'\'')				//get the column programmatic name
				}
				return msg.join(',')							//return the string of fields
		}
	]

The columns are created in the same maner but instead of getting just the column Item Name we get the column Title (nvc.getTitle() as well)

var columns=[
	#{javascript:
			var view:NotesView = database.getView(compositeData.theViewName)
			var msg=[];
			for (var i=1; i<view.getColumnCount()+1; i++){
				var nvc:NotesViewColumn = view.getColumn(i);
				//Create the JSON object containing the column programmatic name and the column title form the view
				msg.push('{header: \''+nvc.getTitle()+'\', sortable: true, dataIndex: \''+nvc.getItemName()+'\'}')
			}
			return msg.join(',')
		}
	]

I added the REST control to the Custom Control itself for simplicity and to make it more portable. This does have the restriction (at this time) of only having one grid on a page at a time. The pathInfo and id of a REST control cannot apparently be computed at build time so I have to keep them static. I am sure there is a way around it…in the mean time the viewName is passed in via compositeData as well as the count. As I think about it you could probably give control to the user using scoped variables and have them select the number of documents displayed…but that is for later.

	<xe:restService pathInfo="ccREST" id="restServe1" >
		<xe:this.service>
			<xe:viewJsonService defaultColumns="true" count="${javascript:compositeData.countNum}" viewName="${javascript:compositeData.theViewName}"></xe:viewJsonService>
		</xe:this.service>
	</xe:restService>

The viewName is also passed into the EXTJS code so that it knows where to look for the REST service on the page.

    var store = Ext.create('Ext.data.Store', {
        autoLoad: true,
        autoDestroy: true,
        autoSync: true,
        model: 'Person',
        proxy: {
            type: 'rest',
            url: '#{javascript:facesContext.getExternalContext().getRequest().getRequestURI()+"/ccREST"}',
            reader: {
                type: 'json',
                root: 'items'
            },
            writer: {
                type: 'json'
            }
        }
    });

The EXTJS code is then simplified because we are passing in the fields and columns values already computed above. Below is the code for the whole Custom Control.

<?xml version="1.0" encoding="UTF-8"?>
<xp:view xmlns:xp="http://www.ibm.com/xsp/core" xmlns:xe="http://www.ibm.com/xsp/coreex">
	<script type="text/javascript" src="ext-4.1.1/ext-all.js"></script>
	<link rel="stylesheet" type="text/css" href="ext-4.1.1/resources/css/ext-all.css" />

	<style>
		.icon-user { background-image: url(images/user.png) !important; }
		.icon-add { background-image: url(images/add.png) !important; }
		.icon-delete { background-image: url(images/delete.png) !important; }
	</style>

	<xp:scriptBlock id="scriptBlock1">
		<xp:this.value><![CDATA[

		var fields=[
			#{javascript:
					var view:NotesView = database.getView(compositeData.theViewName)
					var msg=[];
					for (var i=1; i<view.getColumnCount()+1; i++){
						var nvc:NotesViewColumn = view.getColumn(i);
						msg.push('\''+nvc.getItemName()+'\'')
					}
					return msg.join(',')
			}
		]

		columns=[
			#{javascript:
					var view:NotesView = database.getView(compositeData.theViewName)
					var msg=[];
					for (var i=1; i<view.getColumnCount()+1; i++){
						var nvc:NotesViewColumn = view.getColumn(i);
						msg.push('{header: \''+nvc.getTitle()+'\', sortable: true, dataIndex: \''+nvc.getItemName()+'\'}')
					}
					return msg.join(',')
				}
			]

		Ext.Loader.setConfig({
		  enabled : true,
		  disableCaching : false
		});

		Ext.require([
		             	'Ext.data.*',
		             	'Ext.grid.*',
		             	'Ext.ux.grid.FiltersFeature'
		         ]);

		Ext.define('Person', {
		    extend: 'Ext.data.Model',
		     fields: fields
		});

		Ext.onReady(function(){

		    var store = Ext.create('Ext.data.Store', {
		        autoLoad: true,
		        autoDestroy: true,
		        autoSync: true,
		        model: 'Person',
		        proxy: {
		            type: 'rest',
		            url: '#{javascript:facesContext.getExternalContext().getRequest().getRequestURI()+"/ccREST"}',
		            reader: {
		                type: 'json',
		                root: 'items'
		            },
		            writer: {
		                type: 'json'
		            }
		        }
		    });

		    var local = true;

		     var filters = {
		        ftype: 'filters',
		        // encode and local configuration options defined previously for easier reuse
		        //encode: encode, // json encode the filter query
		        local: local   // defaults to false (remote filtering)

			};

		    var grid = Ext.create('Ext.grid.Panel', {
		        renderTo: 'gridHere',
		        frame: true,
		        features: [filters],
		        height: 400,
		        title: 'Users',
		        store: store,
		        iconCls: 'icon-user',
		        columns: columns
		    });
		});
			]]></xp:this.value>
	</xp:scriptBlock>

	<xe:restService pathInfo="ccREST" id="restServe1" >
		<xe:this.service>
			<xe:viewJsonService defaultColumns="true" count="${javascript:compositeData.countNum}" viewName="${javascript:compositeData.theViewName}"></xe:viewJsonService>
		</xe:this.service>
	</xe:restService>
</xp:view>

Results

As you can see below – a grid, same as we had before.

extjs33

But now we can add a new column to view and without changing the control itself the new column appears on the web.


ext34

ext35

And even complex columns with combined field values.

ext37 ext36

Conclusions

With this Custom control we are able to begin to create the ability to add these EXTJS grids to our XPages, very quickly and very effectively. As we go through the series I will update the custom control with the new capabilities as we look at new grids. Eventually we will have a plethora of controls which can be used to create powerful grids in next to no time at all.

In the mean time you can download the control from the sample database and play with it yourself. http://demo.xomino.com/xomino/Extjs.nsf

How to easily clear your windows printer queue

You know that moment when you have to desperately have to print something and there is a job in the printer queue which will not die without a restart of your computer and/or the printer and you curse and sear about how much you hate windows and printers??????

Copy the following into a text file and save as KillPrintQueue.cmd

net stop spooler
del %systemroot%\system32\spool\printers\*.shd
del %systemroot%\system32\spool\printers\*.spl
net start spooler

save it in your dropbox so you don’t lose it from machine to machine.

 

Run it

 

JOY TO THE WORLD !!!!

EXTJS in XPages #2 – Basic Grid capabilities

In this article I will demonstrate the basic out of the box functionality which comes with each grid and will focus on the capabilities of each column.

Introduction

In the previous article I demonstrated how to add a basic grid to your XPage using the EXTJS grid control and the ExtLib REST service. What we will look at in this article is the basic capabilities of the view columns.

Re-sizing columns

If you mouse over a column separator at the top you will see a familiar icon – clicking on the separator you can drag and drop the column increasing and decreasing the size

ext11 ext12 ext13

Re-ordering of columns

If you click on a column and “drag it” over to the left and right you can re-order them.

ext21

ext22

ext23

Hiding columns

If you mouse over the top right of a column you will see a drop down icon appear – click on it and you will be able to hide one of the columns. You can actually programmatically hide the columns when the grids open and have the users make them visible later if you want to.

ext25

ext26

Sorting Columns

If you click on the column header – or click on the small drop down and select to order the column you can do that

ext24

Filtering Columns

Well ok this is not a BASIC feature of the grid as it is added as another required library – but I figured I would show it cos it is COOL and should be a basic premise of the grids you create. Code will be provided in a later article but for now just know that it can be done locally (filtering the grid contents) and remotely (asking the server for a filtered results set) and it is in the basic demo site


ext6ext7ext8

Demonstration

Go look at the basic demo site and see for yourself.