Nessun risultato. Prova con un altro termine.
Guide
Notizie
Software
Tutorial

Ext.js: l'oggetto Grid - Opzioni di base

Esaminiamo da vicino il componente del noto framework utile alla rappresentazione dinamica di dati tabulari
Esaminiamo da vicino il componente del noto framework utile alla rappresentazione dinamica di dati tabulari
Link copiato negli appunti

Anche le griglie meritano di essere trattate nel dettaglio come gli ultimi elementi dei nostri articoli su Ext.js. Prima dell'avvento dei framework Javascript collocare elementi in una griglia significava creare elementi table nel nostro codice.

Personalizzare le dimensioni, le posizioni, la presenza o l'assenza di una colonna, o l'ordinamento dei dati in tabella, significava dover ridisegnare la pagina e assegnare attributi width ed height a ogni colonna, oltre ad altri pesanti accorgimenti.

Se si voleva creare griglie più elaborate, si doveva ricorrere ad applet Java o ActiveX Windows che abilitassero la possibilità di visualizzare elementi più dinamici ma più pesanti, poco flessibili e poco portabili. Le griglie di Ext, visibili su questa pagina, sono quanto di più dinamico si possa immaginare in ambito DHTML. Le colonne sono ridimensionabili, mobili, possono essere fatte scomparire e apparire facilmente e, se usiamo le variabili di stato in maniera opportuna, un utente può anche facilmente memorizzare le caratteristiche che preferisce tramite cookie o altre strategie che si appoggiano su database o simili.

Differenti tipologie di griglia

Ext ci aiuta a poter creare molte tipologie di griglie differenti. Possiamo caratterizzare le nostre griglie, infatti, con attributi che rendono editabili le celle della griglia, oppure possiamo creare delle griglie con elementi raggruppabili (come in un client di posta, per esempio), o ancora è possibile creare griglie con una colonna di checkbox iniziale, utile a selezionare più elementi contemporaneamente.

Si possono caricare i dati tramite una struttura Javascript semplice interna alla nostra pagina js. Oppure è possibile lanciare chiamate Ajax che caricano le nostre griglie dinamicamente, in modo da poter gestire anche la paginazione dei dati; è possibile caricare i dati da un file XML e mappare in maniera intuitiva la struttura del file XML con una griglia che espone i contenuti in maniera master-detail, ovvero: a fronte della selezione di una riga, verrà mostrato un pannello con dati organizzati in un template utile a dettagliare le poche informazioni presenti nella griglia. Proprio un esempio come questo sarà trattato più nel dettaglio nel corso di questo articolo.

Lo store

Il primo elemento utile a descrivere una grigliaè il suo contenuto. Come riempirla e come formattare gli elementi che verranno mostrati in tabella, è compito dello store.

La classe Store incapsula una cache client side di record di oggetti che forniscono dati di input per i componenti, come il GridPanel, la ComboBox, o il DataView. Un oggetto Store utilizza un oggetto che viene chiamato DataProxy per accedere ai dati. Questa classe è una base astratta per implementazioni che prevedono il recupero di dati non formattati. Le implementazioni di DataProxy sono utilizzate in combinazione con un oggetto Ext.data.DataReader (costruito ad hoc a seconda dell'oggetto che devono andara a leggere -ad esempio possono interpretare oggetti JSON o XML). Quello che viene poi creato da un DataProxy è un blocco di Ext.data.Records che tornano finalmente al nostro Ext.data.Store. Un oggetto Store non è a conoscenza del formato dei dati restituiti dal proxy.

Il column model

Il secondo oggetto fondamentale nella costruzione di una griglia è il ColumnModel. Questa classe viene inizializzata con un array di oggetti colonna utili alla configurazione dell'intera griglia.

Una particolare configurazione definisce la stringa di intestazione della colonna stessa, il campo Ext.data.Record di dati da associare e una funzione opzionale di rendering personalizzata per aggiustare date o per colorare il testo o lo sfondo a seconda di ciò che è presente nel dato, oppure ancora per associare immagini a una cella a seconda di cosa contiene.

La capacità di applicare una classe CSS a tutte le celle di una colonna attraverso il suo id è un'altra delle opzioni di configurazione con cui possiamo formattare il contenuto della nostra griglia in maniera indipendente dai dati. In questo modo applicheremo a pieno il valido pattern MVC (model, view, controller) utile a distinguere per bene dati, visualizzazione e informazioni di business, tra loro.

var colModel = new Ext.grid.ColumnModel([
	{header: "Settore", width: 60, sortable: true},
	{header: "Azienda", width: 150, sortable: true},
	{header: "Fatturato.", width: 100, sortable: true},
	{header: "Previsioni", width: 100, sortable: true, renderer: visualizzaCosti},
	{header: "Impiegati", width: 100, sortable: true, resizable: false}
 ]);

Le opzioni di configurazione definite in questa classe possono comparire in ogni singola colonna, altrimenti viene affidato loro il valore dio default. Ad esempio, sortable o hideable sono due attributi che determinano se la colonna può lanciare un evento di ordinamento dei dati o se può essere nascosta o meno; di default sono due attributi con valore true.

Un esempio pratico

Per cominciare ad andare più a fondo nella descrizione delle griglie, vedremo un esempio relativamente semplice che ci aiuta a mostrare il contenuto di un file .xml strutturato come segue in una tabella master-detail:

<?xml version="1.0" encoding="UTF-8"?>
<Articles>
   
	
	<Article>
		<PageUrl>
http://www.ictv.it/file/vedi/728/creare-un-home-page-a-tab-con-ext/
		</PageUrl>
		<UrlSnippet>
		http://www.ictv.it/code_download/728_code.zip
		</UrlSnippet>
		<ArticleAttributes>
			<Author>Nunzio Fiore</Author>
			<Type>CODE-IT</Type>
			<Title>Creare una homepage a tab con Ext</Title>
			<Site>icTV</Site>
			<Category>VIDEO</Category>
			<HasSnippet>SI</HasSnippet>
			<Lang>ITA</Lang>
			<Description>Come creare un semplice layout Ext e predisporre delle schede a tab per il nostro sito in pochi minuti.</Description>
		</ArticleAttributes>
     </Article>

	 ...
</Articles>
   

Per poter utilizzare codice Ext nelle nostre pagine, basta includere le tre librerie principali che definiscono oggetti e strutture CSS:

	<link rel="stylesheet" type="text/css" href="../ext/resources/css/ext-all.css" />
 	<script type="text/javascript" src="../ext/adapter/ext/ext-base.js"></script>
   <script type="text/javascript" src="../ext/ext-all.js"></script>

A questo punto ci affidiamo completamente alle capacità di Ext di aiutarci a generare codice non-obtrusive e definiamo esclusivamente un div con un id specifico (ad es. binding-example) che ci sarà utile nel codice Javascript per poter mappare il nostro oggetto dinamico con un layer che abbiamo collocato, tramite CSS, nella nostra pagina, indipendentemente dal contenuto complesso che andremo ad includervi:



		<div id="binding-example"></div> 
	

Nel file Javascript attraverseremo nel dettaglio tutte le fasi che abbiamo elencato utili alla creazione della nostra prima griglia. Abbiamo scelto di costruire un esempio molto pulito e semplice in modo da poter analizzare istruzione dopo istruzione ciò che avviene durante la creaszione di un oggetto Ext.GridPanel. Coglieremo l'occasione per rinfrescare anche alcuni concetti che abbiamo visto nelle scorse occasioni, e vedremo in questo modo le caratteristiche salienti di una griglia.

Cominciamo quindi ad istruire il nostro browser perché inizi a renderizzare le componenti Ext nel momento in cui la pagina è stata caricata e l'oggetto Ext, creato grazie all'inclusione di ext-all.js e ext-base.js, ci conferma di essere pronto:

Ext.onReady(function(){

Successivamente inseriamo una componente opzionale, ma molto utile per vedere un oggetto che studieremo più avanti: Ext.state.Manager. Questo oggetto è utile a memorizzare delle caratteristiche utili a descrivere gli oggetti Ext; in questo caso avremo una descrizione completa del columnModel, la presenza, la dimenzione, la posizione delle colonne e molto altro ancora. Nella versione più semplice e base di Ext, abbiamo l'Ext.state.CookieProvider. Questo oggetto ci permette di inizializzare un cookie pe rogni oggetto memorizzato contentente informazioni che possono essere decoficicate in Ext in un oggetto JSON. Nel nostro caso abbiamo istruito il CookieProvider perche' scada dopo 10 anni:

	var cp = new Ext.state.CookieProvider({
       path: "/",
       expires: new Date(new Date().getTime()+(1000*60*60*24*3650))
   })
   Ext.state.Manager.setProvider(cp);

Vediamo ora un'istruzione che abbiamo esaminato nell'articolo riguardante i temi e i layout. Con Ext.util.CSS riusciamo a dire al browser di associare un tema particolare a ogni oggetto mostrato nella nostra pagina. Il tema in questione è descritto completamente nel file che troviamo a questo path ../ext/resources/css/xtheme-gray.css:

	Ext.util.CSS.swapStyleSheet('theme', '../ext/resources/css/xtheme-gray.css'); 

Dopo aver inizializzato quindi il nostro ambiente possiamo passare a descrivere subito l'oggetto che sta alla base di una griglia, ovvero lo store.

Per inizializzarlo basta creare un'istanza di Ext.data.Store tramite la keyword new.

Uno dei primi attributi che andiamo a definire è url; qui facciamo puntare al file article.xml di cui parlavamo prima. Subito dopo istruiamo l'oggetto a capire che dovrà leggere il contenuto di ciò che trova in url come un file Xml. Pertanto associamo all'attributo reader un'istanza di Ext.data.XmlReader. Nella descrizione degli attributi di XmlReader troviamo una completa mappatura dei tag xml, in modo che lo store riesca a parserizzare il file xml e i suoi contenuti e associ un oggetto Ext.data.Record ad ogni elemento del file xml:

	
    // create the Data Store
    var store = new Ext.data.Store({
        // load using HTTP
       url: 'data/articles.xml',

        // the return will be XML, so lets set up a reader
        reader: new Ext.data.XmlReader({
           // records will have an "Article" tag
           record: 'Article',
           id: 'ASIN',
           totalRecords: '@total'
       }, [
           // set up the fields mapping into the xml doc
           // The first needs mapping, the others are very basic
           {name: 'Author', mapping: 'ArticleAttributes > Author'},
		   'Title',
           'Site',
		   'Type',
		   'Category',
		   'HasSnippet',
		   // Detail URL is not part of the column model of the grid
		   'Lang',
		   'PageUrl',
		   'UrlSnippet',
		   'Description'
       ])
    });

Una volta descritto uno store, si può cominciare a descrivere un GridPanel:

    // create the grid
    var grid = new Ext.grid.GridPanel({

A cui viene associato lo store creato precedentemente. Notiamo come la parola store compaia sia dalla parte del nome dell'attributo che dalla parte in cui rappresenta il nome della variabile che contiene lo store:

		store: store,

Arriviamo finalmente a descrivere la seconda componente più importante delle griglie: il ColumnModel. All'interno dell'array che elenca le colonne che troveremo in tabella, vediamo alcuni attributi importanti: header, width, dataIndex, sortable. Ce ne sono molti altri e sono disponibili a questo indirizzo. Quelli che vediamo qui sono tra i più utili e semplici per iniziare. In header viene descritta la stringa che troveremo nell'intestazione di ogni colonna della nostra griglia; in width vediamo la dimensione di default che chiediamo di assegnare alla colonna nel caso in cui non sia stata memorizzata una dimensione dall'utente tramite drag&drop e resize. Se l'utente fa una modifica alla tabella, per come la stiamo creando, questa modifica viene registrata su cookie; pertanto se l'utente torna sulla tabella vede la propria dimensione piuttosto che quella di default. DataIndexè una caratteristica che mappa la colonna con il nome che abbiamo associato a ogni elemento del Record che abbiamo descritto in precedenza. Sortable, l'abbiamo descritto in precedenza, attiva o stoppa l'orindamento dei dati:

	columns: [
	        {header: "Title", width: 220, dataIndex: 'Title', sortable: true},
			{header: "Site", width: 100,dataIndex: 'Site', sortable: true},
	        {header: "Type", width: 50, dataIndex: 'Type', sortable: true},
			{header: "Category", width: 50, dataIndex: 'Category', sortable: true},
    		 {header: "Lang", width: 50,dataIndex: 'Lang', sortable: true},
	        {header: "Snip", width: 50, dataIndex: 'HasSnippet', sortable: true},
		   {header: "Author", width: 60, dataIndex: 'Author', sortable: true}
	        ],

Ci sono diverse caratteristiche di selezione che possono essere associate a un grid. Nel nostro esempio abbiamo deciso di creare una tabella che permetta una selezione alla volta per ogni riga della griglia. Infine abbiamo inserito le ultime caratteristiche utili a persponalizzare il nostro esempio. Con forceFit uguale a true, istruiamo la tabella a occupare tutto lo spazio che le viene messo a disposizione; gli altri attributi sono simili a quelli che abbiamo descritto quando abbiamo parlato delle componenti
panel e window:

		sm: new Ext.grid.RowSelectionModel({singleSelect: true}),
		viewConfig: {
			forceFit: true
		},
        height:310,
		split: true,
		region: 'north'
    });
	

La peculiarità del nostro esempio è data dal Template. Dato che stiamo costruendo una tabella Master/Detail, abbiamo bisogno di un oggetto che descriva come distribuire all'interno del pannello di dettaglio le informazioni contenute nel file xml e che non necessariamente compaiono in griglia. La sintassi un template è molto semplice. Vengono utilizzate le parentesi graffe per racchiudere le parti variabili del codice HTML che inseriamo nell'array del template, successivamente l'array viene associato come argomento dell'istanza di Ext.Template:

	// define a template to use for the detail view
	var articleTplMarkup = [
		'<b>Title</b>: <a href="{PageUrl}" target="_blank">{Title}</a><br/>',
		'<b>Author</b>: {Author}<br/>',
		'<b>Lang</b>: {Lang}<br/>',	
		'<b>Type</b>: {Type}<br/>',	
		'<b>Site</b>: {Site}, {Category}<br/>',
		'<b>Description</b>: {Description}<br/>',
		'<b>Has a snippet for download</b>: {HasSnippet}<br/> ',
		'<a href="{UrlSnippet}" target="_blank">{UrlSnippet}</a>',	
	];

	var articleTpl = new Ext.Template(articleTplMarkup);

Finalmente arriviamo a creare il Panel che verrà collegato tramite l'attributo renderTo con il div con id binding-example che abbiamo visto in precedenza:

	var ct = new Ext.Panel({
		renderTo: 'binding-example',
		frame: true,
		title: 'Article List',
		width:800,
		height: 600,
		layout: 'border',

Il pannello che abbiamo creato ha un layout di tipo border. La griglia che abbiamo descritto in precedenza aveva un attributo region uguale a north, pertanto, associandolo al Panel ct, tramite l'attributo items, riusciamo a posizionare in alto la griglia e in centro un pannello con id uguale a detailPanel in cui andremo a sovrascrivere il nostro template a fronte di ogni selezione:

		items: [
			grid,
			{
				id: 'detailPanel',
				region: 'center',
				bodyStyle: {
					background: '#fefefe',
					padding: '7px'
				},
				html: '
Please select an article to see additional details.' } ] })

Per creare l'effetto di master/detail dobbiamo quindi recuperare l'evento rowselect associato al selection model della nostra griglia e creare una funzione che sovrascriva il template articleTpl nel corpo del pannello detailPanel, con i dati contenuti nel record r.data:

	grid.getSelectionModel().on('rowselect', function(sm, rowIdx, r) {
		var detailPanel = Ext.getCmp('detailPanel');
		articleTpl.overwrite(detailPanel.body, r.data);
	});

Ultima importante istruzione del nostro esempio è store.load(). Scateniamo così una lettura dell'url descritto in store, i dati associati al record, il record associato al template e così via:

	store.load();
	

L'esempio che abbiamo visto è disponibile per download.

Conclusione

In questo articolo abbiamo analizzato nel dettaglio le caratteristiche basilari di una griglia, nel prossimo potremo affrontare argomenti leggermente piu' complessi come il paging, le griglie editabili, il JsonReader, il GroupingView e il CheckboxSelectionModel.

Ti consigliamo anche