In questo articolo della serie dedicata a Ext.js parleremo dei form, come si realizzano, come si usano e da cosa sono composti.
Elenco delle componenti di un form
Per iniziare a comprendere i form dobbiamo pensare a tutte le componenti che abbiamo utilizzato fino ad ora nei nostri moduli online e a come queste sono state tradotte in Ext. Oltre agli elementi comuni e a cui siamo stati abituati, Ext introduce dei campi innovativi (textarea con testo enriched o calendari per i campi data, etc) che ci permettono di non dover utilizzare funzioni o elementi esterni ad Ext per la validazione e di risparmiare quindi parecchio tempo nell’implementazione delle nostre pagine.
Abbiamo quindi:
Checkbox: checkbox di controllo unico campo. Può essere usato come una sostituzione diretta per la checkbox tradizionale.
CheckboxGroup: un gruppo che contiene diversi controlli Checkbox.
Combo Box: un controllo ComboBox con il supporto per autocomplete, remoto-loading, di paginazione e molte altre caratteristiche
DateField: prevede una data di ingresso con un Ext.DatePicker (un calendario) a discesa automatica e possibilità di validazione complessa della data.
FieldSet: contenitore standard utilizzato per il raggruppamento di più campi di un modulo.
Hidden: per inserire i nostri campi nascosti nel form.
HtmlEditor: una textarea enriched con caratteristiche avanzate per la formattazione del testo, per la validazione e con possibilità di utilizzo di altri plugin Ext per l’inserimento di immagini e tabelle complesse.
NumberField: Un campo di testo numerico che fornisce un controllo automatico dei tasti che possono essere accettati e avanzati controlli di validazione.
Radio: il classico campo radio. Simile al controllo checkbox. Un RadioGroup è gestito automaticamente dal browser se si assegna a ciascun radio in un gruppo lo stesso nome.
Radio Group: un gruppo che contiene diversi controlli Radio.
TextArea: campo di testo multilinea. Può essere usato come una sostituzione diretta per i tradizionali campi di testo, in più aggiunge il supporto per auto-sizing.
TextField: campo di testo tradizionale. Può essere usato come una sostituzione diretta dei campi tradizionali o come classe di base per più sofisticati controlli di input (come Ext.form.TextArea e Ext.form.ComboBox).
TimeField: prevede un orario da inserire nel campo con una lista di tempi a discesa e controlli di validazione automatica di orari.
Validazioni e messaggistica
Analizzeremo insieme alcuni degli esempi rilasciati da Ext per la sezione Form e per i suoi controlli complessi. In tutti questi form vedremo come Ext riesca a farci dimenticare i vecchi controlli Javascript per validazione di date, numeri, presenza di un campo, lunghezza e quant’altro grazie ai meccanismi di validazione associati ad ogni form.
Ogni elemento può provvedere a validarsi da sé per via dei controlli onBlur
. Se questi sono attivati, non appena il cursore abbandona (onBlur
) il campo in questione si può vedere l’elemento contrassegnato da un simbolo di errore nel caso in cui il dato inserito non sia corretto. Questa proprietà viene attivata dal campo booleano (true/false) validateOnBlur
.
Un’altra caratteristica fondamentale di ogni elemento è quella di poter comunque esplicitare un proprio meccanismo di validazione attraverso l’attributo validator
, ovvero una funzione personalizzata di validazione che viene chiamata durante la validazione del campo o del form (il default è null
). Se disponibile, questa funzione sarà chiamata solo dopo che il validatori di base ritornano true. Deve restituire boolean true se il valore è valido o una stringa di messaggio di errore in caso contrario.
Immaginiamo ora di avere un oggetto Ext.form che si chiama dataForm
. Per scatenare la validazione del modulo è sufficiente scrivere la seguente riga di codice: dataForm.getForm().isValid()
.
Se vogliamo che il form scateni l’evento di submit, basterà scrivere: dataForm.getForm().getEl().dom.submit()
.
Come abbiamo detto negli articoli precedenti, ogni oggetto ha una catena di ereditarietà che ne può spiegare i comportamenti. L’oggetto Ext.Form, in particolare, estende Ext.BasicForm. La BasicForm è configurata utilizzando l’initialConfig dei FormPanel - che è l'oggetto di configurazione passato al costruttore. Ciò significa che se si ha un FormPanel e si desidera configurare il BasicForm, sarà necessario inserire delle opzioni di configurazione per il BasicForm nelle proprietà di initialConfig.
FormPanel utilizza un Ext.layout.FormLayout implicito nella sua dichiarazione ed è necessario perché i campi e le etichette funzionino correttamente all'interno del FormPanel.
Per impostazione predefinita, i moduli inviano tramite Ajax, utilizzando una Ext.form.Action. In questa maniera si possono gestire i messaggi di ritorno dal server a fronte di un inserimento o di un update e fare con il nostro panel ciò che i paradigmi Ajax ci hanno insegnato a fare negli ultimi anni.
Esempi pratici
Su questa pagina possiamo recuperare alcuni form che ci aiutano a prendere subito confidenza con questo oggetto. Analizzeremo ora i form presenti in questo esempio.
Questo esempio ci aiuta a vedere quanto è semplice realizzare un form. Il codice che rappresenta il form che vediamo in figura è:
var simple = new Ext.FormPanel({ labelWidth: 75, url:'save-form.php', frame:true, title: 'Simple Form', bodyStyle:'padding:5px 5px 0', width: 350, defaults: {width: 230}, defaultType: 'textfield', items: [{ fieldLabel: 'First Name', name: 'first', allowBlank:false },{ fieldLabel: 'Last Name', name: 'last' },{ fieldLabel: 'Company', name: 'company' }, { fieldLabel: 'Email', name: 'email', vtype:'email' }, new Ext.form.TimeField({ fieldLabel: 'Time', name: 'time', minValue: '8:00am', maxValue: '6:00pm' }) ], buttons: [{ text: 'Save' },{ text: 'Cancel' }] }); simple.render(document.body);
Capiamo subito che il FormPanel si comporta esattamente come i panel che abbiamo visto negli articoli precedenti. Nell’attributo items
, infatti, vediamo succedersi i vari elementi del nostro form e riusciamo a leggere semplicemente ciò che essi rappresenteranno. Alcune particolarità le vediamo nell’oggetto Email
che utilizza l’attributo vtype
(virtual type) che serve a creare una validazione per gli oggetti email (nella seconda parte di questo articolo vedremo nel dettaglio come si crea una validazione virtuale). Inoltre vediamo il campo TimeField
che descrive perfettamente un elenco di orari dalle 8 del mattino alle 6 del pomeriggio. Fino a qualche anno fa, un campo del genere, in autocomplete, non sarebbe stato di così rapida implementazione nemmeno per i più bravi esperti Javascript.
Grazie all’attributo defaultType: 'textfield'
, gli elementi elencati in items
che non presentano caratteristiche di xtype (tipologia: date, time, number, etc) sono rappresentati automaticamente da un textfield.
Raggruppare gli elementi di un form a seconda di ciò che rappresentano è una buona norma che ci aiuta sia a mantenere puliti i nostri moduli oltre che a renderli più utilizzabili da parte dell’utente. Un’altra buona norma è non far comparire ciò che è opzionale e renderlo disponibile solo se l’utente sceglie di vederne il contenuto. Per questi motivi, l’utilizzo dei Fieldset di Ext ci aiuta a disegnare form complessi che mantengono una pulizia e un’usabilità non indifferenti.
Il codice che rappresenta il form in figura 2 è il seguente:
var fsf = new Ext.FormPanel({ labelWidth: 75, url:'save-form.php', frame:true, title: 'Simple Form with FieldSets', bodyStyle:'padding:5px 5px 0', width: 350, items: [{ xtype:'fieldset', checkboxToggle:true, title: 'User Information', autoHeight:true, defaults: {width: 210}, defaultType: 'textfield', collapsed: true, items :[{ fieldLabel: 'First Name', name: 'first', allowBlank:false },{ fieldLabel: 'Last Name', name: 'last' },{ fieldLabel: 'Company', name: 'company' }, { fieldLabel: 'Email', name: 'email', vtype:'email' } ] },{ xtype:'fieldset', title: 'Phone Number', collapsible: true, autoHeight:true, defaults: {width: 210}, defaultType: 'textfield', items :[{ fieldLabel: 'Home', name: 'home', value: '(888) 555-1212' },{ fieldLabel: 'Business', name: 'business' },{ fieldLabel: 'Mobile', name: 'mobile' },{ fieldLabel: 'Fax', name: 'fax' } ] }], buttons: [{ text: 'Save' },{ text: 'Cancel' }] }); fsf.render(document.body);
Possiamo notare come all’interno di items
vengano inseriti due fieldset che a loro volta contengono un attributo items
in cui si succedono gli oggetti del form. I fieldset possono essere rappresentati da checkbox o da elementi che rendono espandibile il fieldset stesso e hanno caratteristiche che possono far comparire già aperto o meno un gruppo di elementi.
Anche se i fieldset e i layout ci aiutano a disporre in maniera ordinate i nostri campi, ciò potrebbe non bastare ai clienti più esigenti; ecco che quindi vediamo tramite questo esempio come si possano disporre tramite un TableLayout gli elementi della nostra pagina. In questo esempio inoltre vediamo il primo esempio di htmleditor. Il codice che rappresenta questo form in particolare è il seguente:
var top = new Ext.FormPanel({ labelAlign: 'top', frame:true, title: 'Multi Column, Nested Layouts and Anchoring', bodyStyle:'padding:5px 5px 0', width: 600, items: [{ layout:'column', items:[{ columnWidth:.5, layout: 'form', items: [{ xtype:'textfield', fieldLabel: 'First Name', name: 'first', anchor:'95%' }, { xtype:'textfield', fieldLabel: 'Company', name: 'company', anchor:'95%' }] },{ columnWidth:.5, layout: 'form', items: [{ xtype:'textfield', fieldLabel: 'Last Name', name: 'last', anchor:'95%' },{ xtype:'textfield', fieldLabel: 'Email', name: 'email', vtype:'email', anchor:'95%' }] }] },{ xtype:'htmleditor', id:'bio', fieldLabel:'Biography', height:200, anchor:'98%' }], buttons: [{ text: 'Save' },{ text: 'Cancel' }] });
I form possono essere disposti anche su più tab. In questo modo le informazioni possono essere distribuite in maniera ancora più pulita e vincolata dalla presenza o meno di dati nel tab precedente. Il codice che rappresenta questo form è il seguente:
var tabs = new Ext.FormPanel({ labelWidth: 75, border:false, width: 350, items: { xtype:'tabpanel', activeTab: 0, defaults:{autoHeight:true, bodyStyle:'padding:10px'}, items:[{ title:'Personal Details', layout:'form', defaults: {width: 230}, defaultType: 'textfield', items: [{ fieldLabel: 'First Name', name: 'first', allowBlank:false, value: 'Jack' },{ fieldLabel: 'Last Name', name: 'last', value: 'Slocum' },{ fieldLabel: 'Company', name: 'company', value: 'Ext JS' }, { fieldLabel: 'Email', name: 'email', vtype:'email' }] },{ title:'Phone Numbers', layout:'form', defaults: {width: 230}, defaultType: 'textfield', items: [{ fieldLabel: 'Home', name: 'home', value: '(888) 555-1212' },{ fieldLabel: 'Business', name: 'business' },{ fieldLabel: 'Mobile', name: 'mobile' },{ fieldLabel: 'Fax', name: 'fax' }] }] }, buttons: [{ text: 'Save' },{ text: 'Cancel' }] });
L’ultimo form dell’elenco è un mix di quanto abbiamo visto nei form precedenti. Il codice non ci è permesso di scriverlo per limiti di spazio ma è possibile recuperare il codice Javascript di tutti e cinque gli esempi su questa pagina.
In particolare troveremo caratteristiche speciali come:
l’attributo allowBlank:true/false
, che determina se un campo è obbligatorio o meno.
allowDecimals
, per i campi number. Possiamo descrivere se un numero accetta decimali e quanti ne accetta.
allowNegative
, per i campi number. Possiamo descrivere se un campo accetta numeri negativi.
invalidText
: il testo che si può inserire come messaggio quando un campo risulta non valido.
Vedere tutte le caratteristiche in un solo articolo è impossibile. Ma in questo modo abbiamo cominciato a muovere i nostri primi passi nell’interazione donataci dal form. Quando dobbiamo utilizzare degli elementi e vogliamo verificarne le caratteristiche, possiamo andare a questo url (http://extjs.com/deploy/dev/docs/) e troveremo piccoli esempi e descrizioni di ogni attributo che ci possa sembrare utile ai nostri scopi.
Conclusioni e anticipazioni
Rimangono ancora da trattare alcuni argomenti perché si possa considerare chiusa questa panoramica sui form. La seconda parte di questo articolo tratterà i seguenti argomenti: Advanced Validation, checkbox/Radio Groups, multiSelect and ItemSelector, e combobox, Basic Combo Box, ComboBox Templates.