Nella prima parte di questo articolo abbiamo visto come dichiarare dei pannelli Ext di tipo FormPanel, come creare dei moduli con differenti layout e una carrellata rapida dei campi che si possono inserire all'interno dei nostri form. In questa parte cercheremo di fare un passo avanti continuando un'analisi degli esempi proposti sul sito di Ext su questa pagina e affrontando dettagliatamente le problematiche di interazione di un elemento.
Validazioni dei campi
Innanzitutto possiamo fare qualche considerazione sulla validazione. Tutti i campi che si possono inserire in un form hanno un attributo validator
che serve a definire la funzione di validazione che si vuole utilizzare al momento del submit (ovvero quando il form riceve un evento che lo porta a inviare i dati all'indirizzo esplicitato nell'attributo url
). Ad esempio:
namePrimary = new Ext.form.TextField({ fieldLabel: 'Name/Group', name: 'namePrimary', allowBlank: true, msgTarget: 'under', validator:function(value){ return yourConditionTesting(value) || 'valore non valido' ; } })
In particolare notiamo come nell'attributo validator
abbiamo definito una chiamata a una funzione a partire dal valore che sta assumendo il nostro campo di testo al momento della validazione messa in OR ( || ) con un messaggio di errore ('valore non valido'). In questo modo il validator assume valore uguale al booleano true
o al messaggio da riportare sul form per segnalare l'invalidità del campo.
Un altro modo per testare la validità di un form è dato dall'istruzione form.isValid()
. Per utilizzarlo nei nostri applicativi potremmo scrivere una funzione Javascript con il codice che segue:
var msg, valid = true; form.items.each(function(field){ msg = field.isValid(true); if(msg !== true ){ //true to suppress invalidMarking alert(field.fieldLabel + ' is invalid:' + msg ); valid = false; } }); return valid;
Esistono molti attributi che possiamo associare a un elemento Ext per poter gestire al meglio la validazione. Alcuni campi speciali, come il campo DateField, o il TimeField, o il NumberField e così via, hanno delle validazioni implicite dettate dal tipo di campo e dai valori che può accettare. Queste funzionalità faranno sicuramente comodo a chi programma da diversi anni nel campo web: è infatti molto piacevole potersi sbarazzare di centinaia di righe di funzioni che determinano se un numero è valido o se una data è scritta correttamente o meno.
Vediamo ora, un rapido elenco di attributi, oltre a validator, che possiamo associare pressappoco a tutti i campi di un form.
allowBlank
: se settato su false trasforma il campo in obbligatorio (il default è true);blankText
: è il messaggio di testo da visualizzare se la validazioneallowBlank
fallisce (il messaggio di default è "Questo campo è obbligatorio");invalidClass
: la classe CSS da utilizzare quando si setta un campo non valido (di default è "x-form-invalid
") ;invalidText
: è il messaggio di testo da visualizzare per settare l'errore nel caso in cui un campo risulti non valido (il default è "Il valore in questo campo non è valido");maxLengthText
: è il messaggio di testo da visualizzare se la lunghezza massima viene superata (il default è "La lunghezza massima di questo campo è x");minLengthText
: è il messaggio di testo da visualizzare se la lunghezza minima di convalida non riesce (il default è "La lunghezza minima di questo campo è x");regex
: un oggetto JavaScript RegExp con cui validare il contenuto di un campo (il default è nullo). Se disponibile, questa regex sarà valutata solo dopo la che tutti i metodi validatori ritornano vero. Se il test fallisce, il campo sarà segnato utilizzando regexText;regexText
: è il messaggio di testo da visualizzare se fallisce il controllo regex (il default è "");validateOnBlur
: questo è un attributo molto utile e permette di effettuare delle validazioni quando il campo perde il focus. Associando una funzione Ajax a questo campo potremmo ad esempio lanciare un controllo lato server che verifica la presenza di un campo in un database o cose simili (il default è true);validationDelay
: il tempo in millisecondi che fa partire la validazione dopo l'input (il default è 250);validationEvent
: l'evento che dovrebbe avviare la validazione. Da impostare a false per disattivare la validazione automatica (il default è "keyup").
Per terminare questo capitolo sulle validazioni semplici, riportiamo ancora due proprietà: format
e nanText
. La prima è associata in particolare ai campi DateField e TimeField. In particolare seguono la formattazione che trovate a questo link. Grazie a questa stringa si possono pilotare le validazioni sul contenuto dei campi data ed ora. La proprietà nanText, invece, riguarda i campi numerici ed è il testo del messaggio da visulizzare nel caso in cui il campo non risulti un numero valido.
Validazione avanzata
Proviamo ora a fare un passo avanti e a vedere come si implementano dei meccanismi di validazione più sofisticati.
Ad esempio possiamo vedere su questa pagina due moduli in cui sono stati implementati un controllo di validità di password e un controllo di validità su un periodo temporale.
Riportiamo di seguito il codice dei due moduli:
var dr = new Ext.FormPanel({ labelWidth: 125, frame: true, title: 'Date Range', bodyStyle:'padding:5px 5px 0', width: 350, defaults: {width: 175}, defaultType: 'datefield', items: [{ fieldLabel: 'Start Date', name: 'startdt', id: 'startdt', vtype: 'daterange', endDateField: 'enddt' // id of the end date field },{ fieldLabel: 'End Date', name: 'enddt', id: 'enddt', vtype: 'daterange', startDateField: 'startdt' // id of the start date field }] }); dr.render('dr'); var pwd = new Ext.FormPanel({ labelWidth: 125, frame: true, title: 'Password Verification', bodyStyle:'padding:5px 5px 0', width: 350, defaults: { width: 175, inputType: 'password' }, defaultType: 'textfield', items: [{ fieldLabel: 'Password', name: 'pass', id: 'pass' },{ fieldLabel: 'Confirm Password', name: 'pass-cfrm', vtype: 'password', initialPassField: 'pass' // id of the initial password field }] }); pwd.render('pw');
Dal codice possiamo estrapolare le ultime due proprietà utili alla validazione:
vtype
: utile a richiamare un virtual type da associare al nostro campo;vtypeText
: utile a mostrare il messaggio di errore a fronte della validazione sul virtual type.
Implementare un virtual type è molto semplice. Nel codice che segue possiamo vedere come sono stati implementati i controlli che settano la data minima ( end.setMinValue(date)
) e massima ( start.setMaxValue(date)
) nei due calendari Ext; e come di seguito sia stato implementato il vtype password
che controlla che le due password digitate siano uguali (var pwd = Ext.getCmp(field.initialPassField); return (val == pwd.getValue());
).
Ext.apply(Ext.form.VTypes, { daterange : function(val, field) { var date = field.parseDate(val); if(!date){ return; } if (field.startDateField && (!this.dateRangeMax || (date.getTime() != this.dateRangeMax.getTime()))) { var start = Ext.getCmp(field.startDateField); start.setMaxValue(date); start.validate(); this.dateRangeMax = date; } else if (field.endDateField && (!this.dateRangeMin || (date.getTime() != this.dateRangeMin.getTime()))) { var end = Ext.getCmp(field.endDateField); end.setMinValue(date); end.validate(); this.dateRangeMin = date; } return true; }, password : function(val, field) { if (field.initialPassField) { var pwd = Ext.getCmp(field.initialPassField); return (val == pwd.getValue()); } return true; }, passwordText : 'Passwords do not match' });
Checkbox/Radio Groups
La nuova versione di Ext ha aggiunto alcune utility per la gestione dei pulsanti checkbox e radio. Queste utility sono visualizzabili su questa pagina. L'esempio mostra gruppi di pulsanti radio e checkbox raggruppati tra di loro in molti modi. Per definire un gruppo di pulsanti a scelta multipla (checkbox) basta elencarli nel consueto attributo/array items
e collegarli con un xtype di tipo checkboxgroup
:
{ // Use the default, automatic layout to distribute the controls evenly // across a single row xtype: 'checkboxgroup', fieldLabel: 'Auto Layout', items: [ {boxLabel: 'Item 1', name: 'cb-auto-1'}, {boxLabel: 'Item 2', name: 'cb-auto-2', checked: true}, {boxLabel: 'Item 3', name: 'cb-auto-3'}, {boxLabel: 'Item 4', name: 'cb-auto-4'}, {boxLabel: 'Item 5', name: 'cb-auto-5'} ] }
Per creare un radiogroup si procede in maniera analoga al codice precedente, sostituendo semplicemente l'xtype.
Le combobox
Per esaminare in maniera completa le potenzialità delle combobox in Ext non basterebbe lo spazio di due articoli. Grazie alle potenzialità di questo framework, infatti, le combobox diventano un utile strumento di lavoro all'interno dei nostri moduli. Possiamo infatti costruire elenchi a partire da una lista di dati interna alla nostra pagina, o da un array Javascript, o da una chiamata Ajax. Quest'ultima può essere implementata in modo che la richiesta che parte verso il server crei un effetto in stile autocomplete: lato server viene effettuata una ricerca a seconda di quello che stiamo digitando e la nostra combobox mostra una tendina con i valori di ritorno della ricerca che divengono più specifici mano a mano che la parola ricercata va a completarsi.
Basic Combo Box
Possiamo vedere qualche esempio di combobox molto semplice a questo link. La più facile e immediata in assoluto è la seguente:
// simple array store var store = new Ext.data.SimpleStore({ fields: ['abbr', 'state', 'nick'], data : Ext.exampledata.states // from states.js }); var combo = new Ext.form.ComboBox({ store: store, displayField:'state', typeAhead: true, mode: 'local', forceSelection: true, triggerAction: 'all', emptyText:'Select a state...', selectOnFocus:true, applyTo: 'local-states' });
Nella struttura dati chiamata store
, ottenuta tramite la creazione di un'istanza di SimpleStore, vengono introdotti tre campi; questi tre campi vengono poi valorizzati da una lista di dati ottenuta dal file states.js. A questo punto la struttura store viene utilizzata come elemento di store (appunto) della nostra combobox, a cui vengono associate alcune caratteristiche interessanti. Ad esempio una caratteristica molto utile è l'emptyText, ovvero il testo che viene inserito nella nostra combobox fino a quando non si va e si comincia a scrivere il valore che stiamo cercando. Un'altra caratteristica che possiamo notare è che la Ext.form.ComboBox viene associata nella nostra pagina HTML a un elemento di tipo input type text. Nei prossimi articoli vedremo come si usano le griglie di Ext e comprederemo piu' cose riguardo agli store di dati, in tale sede riprenderemo in considerazione le combobox e alcune loro caratteristiche:
<input type="text" id="local-states" size="20"/>
Altre caratteristiche sono molto semplici e intuitive. Si possono comunque trovare elencate su questa pagina.
ComboBox Templates
Un aspetto associato alle combobox che deve essere tenuto in considerazione è la capacità di queste ultime di essere associate ad un template HTML. L'uso dei template è riccorrente in Ext. Per chi ha lavorato con strumenti come Velocity di Apache o altri strumenti Java, la sintasssi dei template può risultare piuttosto intuitiva. Anche chi non ha conoscenze di disegno di template può comprenderli semplicemente. Basta capire che le parti variabili in un template sono racchiuse tra parentesi graffe e che ciò che è contenuto nelle parentesi è un comando o una variabile.
Possiamo vedere, per esempio, il codice su questa pagina.
Vediamo infatti come qualsiasi campo possa risultare una combobox e come a un campo di testo si possa associare un template complesseo per esporre i risultati di una ricerca Ajax. In particolare il template utilizzato nell'esempio esposto nel link è il seguente:
// Custom rendering Template var resultTpl = new Ext.XTemplate( '<tpl for="."><div class="search-item">', '<h3><span>{lastPost:date("M j, Y")}<br />by {author}</span>{title}</h3>', '{excerpt}', '</div></tpl>' );
Il risultato di questo template è un insieme di rige che hanno una formattazione del campo data (lastPost
), e a capo il nome dell'autore e il titolo del post associato.
MultiSelect and ItemSelector
Per concludere la nostra rapida carrellata delle funzioni Ext, possiamo vedere le liste di dati e come vengono gestite. Nella versione attuale di Ext troviamo questi due componenti grazie al contribuito a Ext del membro della community TJ Stuart.
Il multiselect è un elenco che consente di selezionare più elementi di una lista, e l'ItemSelector combina due MultiSelects in un più sofisticato controllo che include drag&drop.
Bisogna precisare che per il momento questi controlli sono ancora implementati come estensioni e che la multiselect sarà probabilmente migrata in una componente fondamentale in un futuro rilascio. Per vedere due esempi concreti che utilizzano questa componente basta andare a questo indirizzo.
Conclusione
In questi due articoli abbiamo avuto modo di visionare rapidamente i maggiori componenti di un modulo. Abbiamo ritenuto utile soffermarci di più su alcuni aspetti come la validazione che possono essere personalizzati a seconda delle nostre esigenze. Le altre componenti che abbiamo visto sono molto simili tra loro e una volta comprese le caratteristiche comuni (dato che sono tutte un'estensione di field) ogni utente potrà utilizzarle in maniera rapida nei propri moduli. La componente che più potrà essere customizzata e resa unica a seconda del progetto o del sito che stiamo sviluppando rimane la combobox, che potrà mostrarci liste, tabelle e dati che possono essere formattati in maniera rapida, velocizzando il disegno delle nostre GUI e l'interazione tra utente e parte server dei nostri applicativi.