Blog2j
 
Cerca con Google
Ricerca personalizzata
 
Griglia Extjs con paginazione, ordinamento e parametri di ricerca

In questo post vediamo come usare una grid di extjs per creare una pagina html che mostra una lista di dati paginati, ordinabili e filtrabili in base a dei criteri di ricerca. La tabella di dati viene popolata con chiamate ajax verso il server sfruttando dwr (vedi il precedente tutorial per i dettagli sull'utilizzo di dwr con spring). La parte di vista è composta da una pagina html quindi gran parte del codice mostrato può essere usato anche in progetti non java (per esempio php o python). I sorgenti dell'esempio sono disponibili qui, lo zip contiene un dynamic web project di eclipse in cui devono essere aggiunti i jar di spring, dwr e commons-logging.

Iniziamo vedendo uno screenshot della pagina completa, in alto sono presenti i parametri di ricerca e in basso la griglia ordinabile con la barra che gestisce la paginazione:

Vediamo il metodo java sul server che viene usato per popolare la tabella di dati. La classe Persona è un bean contenente i campi nome, cognome e età. La signature del metodo che esegue la ricerca è il seguente:

PaginatedList<Persona> cerca(int start, int limit, String nome, 
String cognome, Integer eta, String sort, String dir)

I parametri passati sono:

  • start: indice del primo elemento da ritornare
  • limit: numero di elementi da ritornare
  • nome: filtro opzionale sul campo nome
  • cognome: filtro opzionale sul campo cognome
  • età: filtro opzionale sul campo età
  • sort: campo su cui eseguire l'ordinamento dei dati
  • dir: tipo di ordinamento (ascendente o discendente)

Il metodo ritorna una istanza della classe PaginatedList e non una semplice lista in quanto il metodo esegue anche la paginazione dei dati. Questa classe contiene sia la lista di elementi trovati che il numero totale di elementi trovati:

public class PaginatedList<T> {

	private List<T> items;
	private int totalCount;
	//getter e setter...
}

Passiamo a vedere la pagina html che contiene la lista di dati, contiene le inclusioni di tutti i file css e javascript necessari nell'header mentre il body è composto semplicemente un div che verrà riempito runtime da extJs:

<html>
<head>
<title>Grid extJs</title>

<script type='text/javascript' src='dwr/interface/personaDAO.js'></script>
<script type='text/javascript' src='dwr/engine.js'></script>

<link rel="stylesheet" type="text/css" href="http://cachefile.net/scripts/ext/2.0.2/resources/css/ext-all.css" />

<script type='text/javascript' src='http://cachefile.net/scripts/ext/2.0.2/adapter/ext/ext-base.js'></script>
<script type='text/javascript' src='http://cachefile.net/scripts/ext/2.0.2/ext-all.js'></script>

<script type='text/javascript' src='js/dwrProxy.js'></script>
<script type='text/javascript' src='js/blog2jGridExample.js'></script>

</head>
<body>
	<div id="grid-example" style="padding-left: 20px;padding-top: 20px;"></div>
</body>
</html>

I file inclusi sono i seguenti:

  • personaDAO.js e engine.js: codice javascript di dwr per interagire con il server
  • ext-all.css: css di extJs
  • ext-base.js e ext-all.js: codice sorgente javascript di extJs
  • dwrProxy.js: proxy che permette di popolare i dati di una griglia di extJs con dwr (vedi post sul forum di extJs per i dettagli)
  • blog2jGridExample.js: codice scritto per questo esempio

Iniziamo a vedere il contenuto di quest'ultimo file, per quelli non troppo ferrati con il javascript una utile lettura è il tutorial javascript di blog2j.

Tutte le chiamate di inizializzazione della pagina di extJs sono solitamente contenute dentro una function passata al metodo Ext.onReady, la function passata viene eseguita al momento giusto, ovvero quando sono stati scaricati tutti i javascript e prima dell'evento onload della pagina.

Ext.onReady( function() {
	//inizializzazione della pagina
});

L'oggetto Ext contiene molte function di utilità, per esempio Ext.get ritorna un oggetto che incapsula un elemento della pagina, Ext.id genera un id univoco e Ext.extend permette di creare gerarchie di classi.

Una grid extJs contiene al suo interno vari oggetti javascript, il primo che incontriamo in questo esempio è il proxy che è l'oggetto che si occupa di reperire i dati. Esistono varie classi proxy, una delle più usate è HttpProxy che permette di reperire i dati con chiamate ajax verso il server. Come già detto in questo esempio usiamo una istanza di DWRProxy che permette di richiamare il metodo javascript di dwr passato nella configurazione del costruttore:

	var dwrProxy = new Ext.ux.data.DWRProxy( {
		dwrFunction :personaDAO.cerca
	});

L'oggetto reader si occupa di interpretare i dati letti dal proxy, esistono le classi XmlReader e JsonReader che gestiscono i formati xml e json. Queste classi prendono come parametri del costruttore una configurazione e un record che definisce i campi da leggere.

	var record = Ext.data.Record.create( [ {
		name :'nome'
	}, {
		name :'cognome'
	}, {
		name :'eta'
	} ]);
	var jsonReader = new Ext.data.JsonReader( {
		root :'items',
		totalProperty :'totalCount'
	}, record);

Lo store è il modello dei dati della tabella (la m del pattern mvc). La configurazione passata al costruttore contiene varie informazioni fra cui il proxy e il reader da usare e un oggetto che indica come ordinare i dati.

	var store = new Ext.data.Store( {
		remoteSort :true,
		proxy :dwrProxy,
		reader :jsonReader,
		sortInfo : {
			field :'nome',
			direction :'ASC'
		}
	});

Il columnModel definisce le varie colonne usate nella tabella, per ogni colonna è possibile specificare varie proprietà fra cui l'header, la larghezza, l'allineamento, il dataIndex (ovvero il corrispondente campo dello store da mostrare), un tooltip e due flag che indicano se la colonna è ordinabile e ridimensionabile.

	var columnModel = new Ext.grid.ColumnModel( [ {
		header :"Nome",
		width :200,
		dataIndex :'nome'
	}, {
		header :"Cognome",
		width :200,
		dataIndex :'cognome'
	}, {
		header :"Età",
		width :75,
		dataIndex :'eta'
	} ]);
	columnModel.defaultSortable = true;

Questo esempio gestisce anche la paginazione dei dati, la barra sulla griglia in basso è una PagingToolbar che contiene i tasti per scorrere le varie pagine e le informazioni sulla pagina corrente:

	var barraPaginazione = new Ext.PagingToolbar( {
		pageSize :15,
		store :store,
		displayInfo :true,
		displayMsg :'Elementi {0} - {1} di {2}',
		emptyMsg :"Nessun elemento trovato"
	});

Siamo arrivati al momento di mettere insieme tutti gli oggetti visti fino ad adesso per creare un GridPanel:

	var grid = new Ext.grid.GridPanel( {
		store :store,
		cm :columnModel,
		viewConfig : {
			//lo spazio che avanza viene suddiviso fra le colonne
			forceFit :true
		},
		//alterno i colori delle righe
		stripeRows :true,
		//l'altezza del pannello viene impostata in base al numero di righe 
		autoHeight :true,
		bbar :barraPaginazione
	});

Dalla versione 2.0 extJs mette a disposizione una gestione dei pannelli simile a quella di un framework per sviluppare applicazionni desktop (per esempio swing o .net). Esistono varie implementazioni della classe Panel, oltre a GridPanel appena vista esiste FormPanel per creare form html, TreePanel per creare alberi e Window per creare popup in javascript.

Tutti i panel accettano in input nei parametri del costruttore una lista di componenti (proprietà items) e una lista di buttons. I componenti sono organizzati all'interno di un pannello in base al layout impostato, i layout disponibili sono absolute, accordion, anchor, border, card, column, fit, form and table.

I parametri di ricerca in questo esempio sono inclusi in un FieldSet che permette di raggruppare campi in un riquadro con un titolo. La lista di items di un panel può essere composta da oggetti derivati da Component o semplicemente da configurazioni di oggetti.

	var parametriRicerca = new Ext.form.FieldSet( {
		title :'Parametri di ricerca',
		defaultType :'textfield',
		autoHeight :true,
		collapsible :true,
		items : [ {
			fieldLabel :'Nome',
			name :'nome',
			anchor :'100%'
		}, {
			fieldLabel :'Cognome',
			name :'cognome',
			anchor :'100%'
		}, new Ext.form.NumberField( {
			fieldLabel :'Età',
			name :'eta',
			anchor :'100%',
			xtype :'numberField'
		}) ],
		buttons : [ {
			text :'Cerca',
			handler : function() {
				store.load( {
					params : {
						start :0,
						limit :15
					}
				});
			}
		}, {
			text :'Reset',
			handler : function() {
				parametriRicerca.items.each( function(f) {
					f.reset();
				});
			}
		} ],
		buttonAlign :'center'
	});

I buttons creati sono due, per ognuno sono specificate due proprietà: l'etichetta da mostrare e l'handler da usare (ovvero la function javascript invocata quando viene cliccato il button). Il button cerca richiama il caricamento dei dati sullo store mentre reset scorre tutti i parametri di ricerca specificati e su ognuno invoca il metodo reset. Il costrutto each è molto usato in extJs e permette di scorrere una lista di oggetti invocando su ogni elemento la function passata. Esiste anche il metodo Ext.each che accetta come parametri un array di oggetti da scorrere e una function da invocare su ogni oggetto.

I valori dei parametri di ricerca sono passati al server tramite un evento sullo store:

	store.on('beforeload', function(dataProxy, p) {
		parametriRicerca.items.each( function(f) {
			p.params[f.name] = f.getValue();
		});
	});

Il metodo on è definito nella classe Observable da cui derivano molte delle classi definite in extJs. Observable mette a disposizione una gestione degli eventi semplice ma molto potente attraverso i metodi:

  • addEvents: definisce un evento sull'oggetto
  • addListener (o semplicemente on): registra una function passata in modo che venga invocata quando scatta l'evento
  • fireEvent: invoca le function che si sono registrate per l'evento passando eventuali parametri

All'apertura della pagina viene invocato manualmente il metodo load sullo store per eseguire un caricamento iniziale dei dati:

	store.load( {
		params : {
			start :0,
			limit :15
		}
	});

Infine creiamo un Panel contenente i parametri di ricerca e la griglia e lo renderizziamo nel div contenuto nel body della pagina html:

	var panel = new Ext.Panel( {
		layout: 'anchor',
		width :600,
		border :false,
		items : [ parametriRicerca, grid ]
	});
	panel.render('grid-example');

L'esempio è arrivato alla conclusione, abbiamo visto come utilizzare l'oggetto GridPanel e una mini guida ai principali costrutti usati nel framework extJs. Ulteriori esempi sono disponibili sul sito ufficiale che contiene anche documentazione sul framework.

 
News