La classe Ext.Container rappresenta senza dubbio la sottoclasse di Ext.BoxComponent più importante. Essa permette di costruire widget grafici capaci di contenere a loro volta altri componenti di qualsiasi natura. Grazie a Ext.Component è possibile realizzare interfacce complesse e organizzate in maniera da offrire all'utente applicazioni web funzionali, usabili e sempre di più simili alle corrispettive applicazioni desktop.
Per costruire Ext.Container è necessario impostare la proprietà fondamentale items
la quale incapsulerà (sotto forma di vettore o di oggetto singolo) i componenti contenuti nel widget che si sta per creare. Questa proprietà sfrutta in maniera ottimale il concetto di istanziazione lazy e xtype descritta dettagliatamente nel precedente articolo: infatti è possibile passare come parametri non solo riferimenti ad oggetti ExtJS costruiti grazie al costrutto new
, ma anche semplici oggetti JavaScript contenenti l'attributo xtype
che verranno “trasformati” in oggetti ExtJS automaticamente dal framework solamente quando l'Ext.Container padre verrà renderizzato in pagina. Negli esempi di questo e nei prossimi articoli utilizzerò, come suggerito anche dagli sviluppatori del framework, appunto questo modello di sviluppo.
Le principali sottoclassi di Ext.Container sono Ext.Panel, Ext.TabPanel e Ext.Window e verranno analizzate nel dettaglio nei prossimi articoli.
Il concetto di layout
Definire il layout di un Ext.Container significa definire la modalità attraverso la quale i componenti figli verranno visualizzati all'interno del padre. ExtJS espone una serie di layout out-of-the-box che possono essere utilizzati facilmente. Ciascun layout è rappresentato da una classe appartenente al package Ext.layout.
È possibile comunque implementare il proprio layout estendendo la classe astratta Ext.layout.ContainerLayout.
Per impostare il layout si utilizza la proprietà layout
passando come riferimento una stringa che permette di identificare univocamente un particolare layout. Per configurare un particolare layout (ovviamente solo i più complessi lo permettono) si può agire in determinati modi:
- per impostare particolari attributi al layout nel suo insieme si sfrutta la proprietà dell'Ext.Container padre
layoutConfig
passando come parametro un oggetto composto da chiave/valore (per esempio la proprietà animate nell'AccordionLayout); - per impostare particolari attributi ad un determinato figlio si utilizzano proprietà extra per il componente stesso (extra perché non sono API dirette del figlio ma sono imposte dal tipo di layout scelto – per esempio la proprietà
region
nel BorderLayout ocolumnWidth
nel ColumnLayout).
Ext.layout.FitLayout (“fit”)
Il FitLayout è il layout più semplice e permette di impostare un unico figlio per l'Ext.Container che occuperà l'intero spazio a sua disposizione (ovvero occuperà tutto l'Ext.Container padre).
<html>
<head>
<script src="../extjs/adapter/ext/ext-base.js"></script>
<script src="../extjs/ext-all.js"></script>
<link rel="stylesheet" href="../extjs/resources/css/ext-all.css" />
<script>
Ext.onReady(function() {
var panel = new Ext.Panel({
layout:'fit',
title:'panel',
height: 300,
width: 400,
items: {
xtype:'panel',
title:'panel 2',
layout: 'fit',
items: {
xtype:'panel',
title:'panel 3',
html: 'I'm a panel'
}
}
});
panel.render(Ext.getBody());
});
</script>
</head>
<body>
</body>
</html>
Nell'esempio abbiamo creato 3 Ext.Panel innestati sfruttando il FitLayout. Quest'ultimo è utilizzabile solamente quando il numero dei figli di un Ext.Container è pari a uno.
Ext.layout.AccordionLayout(“accordion”)
L'AccordionLayout permette di impostare i figli di un determinato Ext.Container come una pila di elementi collassabili dei quali solo uno è visibile. Per visualizzare un determinato figlio basterà cliccare sul box contenente il titolo dello stesso.
<html>
<head>
<script src="../extjs/adapter/ext/ext-base.js"></script>
<script src="../extjs/ext-all.js"></script>
<link rel="stylesheet" href="../extjs/resources/css/ext-all.css" />
<script>
Ext.onReady(function() {
var panel = new Ext.Panel({
layout:'accordion',
title:'panel',
height: 300,
width: 400,
layoutConfig: {
animate: true
},
items: [{
xtype:'panel',
title:'panel 2',
html: 'I'm the panel 2'
},{
xtype:'panel',
title:'panel 3',
html: 'I'm the panel 3'
},{
xtype:'panel',
title:'panel 4',
html: 'I'm the panel 4'
}]
});
panel.render(Ext.getBody());
});
</script>
</head>
<body>
</body>
</html>
In questo esempio abbiamo creato un accordion composto da 3 pannelli collassabili e con contenuto differente. Da notare l'utilizzo della proprietà layoutConfig
che permette di modificare il comportamento di default del motore di layout e non del pannello stesso.
Ext.layout.AnchorLayout (“layout”)
L'AnchorLayout permette di “ancorare” i figli di un particolare Ext.Container sulla base delle sue dimensioni. I figli vengono posizionati orizzontalmente all'interno del padre e vengono ridimensionati sulla base dell'attributo anchor.
Questa proprietà accetta valori di diversa natura:
- valori percentuale – il primo valore rappresenta la larghezza percentuale del figlio, il secondo l'altezza percentuale;
- valori interi positivi o negativi – il primo valore rappresenta lo scarto (offset) da utilizzare per la larghezza, il secondo per l'altezza;
- valori rappresentanti un lato (valori possibile “right” o “bottom”) - per allineare il widget lungo il lato selezionato (in questo caso è necessario fissare delle dimensioni al figlio o utilizzare l'attributo a livello di layout anchorSize spiegato sotto).
L'unico attributo appunto per modificare il comportamento del layout è anchorSize
che permette di definire le dimensioni di un Container virtuale utilizzato solamente per il calcolo delle dimensioni dei widget figli.
<html>
<head>
<script src="../extjs/adapter/ext/ext-base.js"></script>
<script src="../extjs/ext-all.js"></script>
<link rel="stylesheet" href="../extjs/resources/css/ext-all.css" />
<script>
Ext.onReady(function() {
var p = new Ext.Panel({
layout:'anchor',
width: 300,
height: 400,
anchorSize: {width:100, height:800},
items:[{
title:'panel 1',
html:'I'm the panel 1',
anchor:'40% 40%'
},{
title:'panel 2',
html:'I'm the panel 2',
anchor:'-10 30%'
},{
title:'panel 3',
html: 'I'm the panel 3',
anchor:'100%'
}]
});
p.render(Ext.getBody());
});
</script>
</head>
<body>
</body>
</html>
Da notare, come nel caso del secondo pannello, è possibile mixare diverse tipologie di valori (nell'esempio un intero negativo ed una percentuale) e, come nel caso del terzo pannello, in caso di mancanza del secondo parametro (altezza) venga utilizzata un altezza automatica sulla base del contenuto.
Nonostante la flessibilità di questo layout, esso è ab
bastanza scomodo da utilizzare e spesso vengono sfruttate le sue sottoclassi: Ext.layout.AbsoluteLayout e Ext.layout.FormLayout.
Ext.layout.AbsoluteLayout (“absolute”)
Questo layout permette di posizionare gli elementi tramite un posizionamento assoluto sfruttando gli indici cartesiani x e y. Oltre a queste proprietà è possibile sfruttare l'attributo anchor
per impostare le dimensioni dei widget.
Ext.layout.FormLayout (“form”)
Il FormLayout permette di organizzare gli elementi di un Ext.Container come se fosse un form quindi utilizzando label, textfield e eventuali icone relative alla validazione. Questo layout è sfruttato automaticamente dall'Ext.form.FormPanel e non dovrebbe mai essere impostato manualmente ad un Ext.Container differente. Lo approfondiremo maggiormente quando tratteremo nel dettaglio i form con ExtJS.
Fine prima parte.
Ext.layout.CardLayout (“card”)
Questo tipo di layout permette di visualizzare un Component alla volta permettendo di switchare tra tutti i figli. Gli utilizzi più comuni sono i classici pannelli a tab (infatti Ext.TabPanel lo implementa di default) o i classici wizard che presentano una serie di pannelli predisposti secondo un ordine ben definito. Una particolarità di questo layout è la presenza di un metodo fondamentale (setActiveItem) che permette appunto di forzare la visibilità di un determinato figlio nascondendone il precedente.
<html>
<head>
<script src="../extjs/adapter/ext/ext-base.js"></script>
<script src="../extjs/ext-all.js"></script>
<link rel="stylesheet" href="../extjs/resources/css/ext-all.css" />
<script>
Ext.onReady(function() {
var panel = new Ext.Panel({
layout:'card',
title:'panel',
height: 300,
width: 400,
items: [{
xtype:'panel',
title:'panel 2',
html: 'I'm the panel 2'
},{
xtype:'panel',
title:'panel 3',
html: 'I'm the panel 3'
},{
xtype:'panel',
title:'panel 4',
html: 'I'm the panel 4'
}],
buttons: [{
text: "panel 1",
handler: function() {
panel.getLayout().setActiveItem(0);
}
}, {
text: "panel 2",
handler: function() {
panel.getLayout().setActiveItem(1);
}
}, {
text: "panel 3",
handler: function() {
panel.getLayout().setActiveItem(2);
}
}]
});
panel.render(Ext.getBody());
panel.getLayout().setActiveItem(0);
});
</script>
</head>
<body>
</body>
</html>
In questo esempio abbiamo creato un mini-wizard composto da 3 passi senza vincoli: basterà cliccare sui bottoni per visualizzare il pannello corrispondente all'interno dell'Ext.Container padre.
Il concetto utilizzato dai TabPanel è esattamente lo stesso dell'esempio.
Ext.layout.BorderLayout(“border”)
Il BorderLayout è il più complesso tra i layout proposti da ExtJS e permette di realizzare ambienti grafici allo stesso tempo piacevoli alla vista e comodi da utilizzare. Un pannello che utilizza questo particolare layout potrà avere da 2 a 5 figli che verranno posizionati lungo i 4 lati più uno centrale che occuperà lo spazio rimanente. Ciascun lato viene identificato tramite il corrispettivo punto cardinale (“north”,”south”,”west”,”ovest”) utilizzando la proprietà region. Non tutti le regioni devono essere popolate con un componente: per realizzare un border layout basta solamente una regione oltre ovviamente a quella centrale.
Oltre alla possibilità di “agganciare” ciascun componente lungo un lato dell'Ext.Container è possibile anche sfruttare la proprietà split
per creare dei widget che siano ridimensionabili, eventualmente settando anche i valori minimi e massimi per il ridimensionamento.
<html>
<head>
<script src="../extjs/adapter/ext/ext-base.js"></script>
<script src="../extjs/ext-all.js"></script>
<link rel="stylesheet" href="../extjs/resources/css/ext-all.css" />
<script>
Ext.onReady(function() {
var panel = new Ext.Panel({
layout:'border',
width: 600,
height: 500,
items: [{
title: 'Center',
region: 'center',
html: 'I'm the center panel'
},{
title: 'West',
html: 'I'm the west panel and you can resize me',
region: 'west',
width: 100,
minWidth: 50,
maxWidth: 150,
split: true
},{
title: 'North',
html: 'I'm the north panel',
region: 'north',
heigth: 30
}, {
html: 'I'm the south panel with no title',
region: 'south',
heigth: 30
}]
});
panel.render(Ext.getBody());
});
</script>
</head>
<body>
</body>
</html>
Nell'esempio abbiamo creato un BorderLayout composto da 4 pannelli. Il pannello a nord presenta un titolo e un'altezza fissa, il pannello a sud presenta un'altezza fissa senza avere il titolo mentre il pannello posizionato ad ovest presenta una larghezza iniziale (100) e la possibilità di resize (split = true
) tra un valore minimo di 50 e un valore massimo di 150. Lo spazio rimanente verrà occupato dal pannello centrale.
Ext.layout.ColumnLayout (“column”)
Il ColumnLayout è un layout abbastanza semplice e permette di suddividere il padre in un numero variabile di colonne ognuna delle quali potrà essere poi riempita con un particolare componente grafico. Per utilizzare questo layout sarà necessario assegnare a ciascun figlio un valore per la proprietà extra columnWidth
per definire la larghezza appunto della colonna occupata. Questo proprietà può essere valorizzata con un numero intero o con un numero decimale. Nel primo caso il valore rappresenterà la larghezza in pixel altrimenti quella in percentuale (esempio).
<html>
<head>
<script src="../extjs/adapter/ext/ext-base.js"></script>
<script src="../extjs/ext-all.js"></script>
<link rel="stylesheet" href="../extjs/resources/css/ext-all.css" />
<script>
Ext.onReady(function() {
var panel = new Ext.Panel({
layout:'column',
width: 500,
items: [{
title: 'Column 1',
html: 'I'm the column number 1',
columnWidth: .2
},{
title: 'Column 2',
html: 'I'm the column number 2',
columnWidth: .6
},{
title: 'Column 3',
html: 'I'm the column number 3',
columnWidth: .2
}]
});
panel.render(Ext.getBody());
});
</script>
</head>
<body>
</body>
</html>
Ext.layout.TableLayout (“table”)
Il TableLayout permette di realizzare strutture tabellari che incapsulano i componenti come se fosse una semplice tabella HTML. Per utilizzare questo layout è necessario definire la proprietà columns
a livello di layout (quindi sfruttando l'attributo layoutConfig)
per comunicare alla classe TableLayout quante colonne vogliamo utilizzare. Oltre a questa semplice impostazione di base è possibile sfruttare, esattamente come nelle tabelle HTML, anche i rowspan e i colspan comunicandoli al framework come attributi aggiuntivi dei componenti figli che andranno a popolare l'Ext.Container esterno (esempio).
<html>
<head>
<script src="../extjs/adapter/ext/ext-base.js"></script>
<script src="../extjs/ext-all.js"></script>
<link rel="stylesheet" href="../extjs/resources/css/ext-all.css" />
<script>
Ext.onReady(function() {
var panel = new Ext.Panel({
layout:'table',
layoutConfig: {
columns: 3
},
width: 400,
items: [{
html: 'I'm the column number 1',
width: 200,
rowspan: 2
},{
html: 'I'm the column number 2',
width: 200,
colspan: 2
},{
html: 'I'm the column number 3',
width: 100
},{
html: 'I'm the column number 4',
width: 100
}]
});
panel.render(Ext.getBody());
});
</script>
</head>
<body>
</body>
</html>
Ext.layout.HBoxLayout (“hbox”) e Ext.layout.VBoxLayout (“vbox”)
Entrambi questi layout permettono di disporre i figli di un Ext.Container rispettivamente orizzontalmente e verticalmente dividendo lo spazio disponibile sulla base dell'attributo numerico flex
. Grazie ad esso possiamo definire in proporzione quanto spazio orizzontale o verticale ciascun figlio occuperà.
<html>
<head>
<script src="../extjs/adapter/ext/ext-base.js"></script>
<script src="../extjs/ext-all.js"></script>
<link rel="stylesheet" href="../extjs/resources/css/ext-all.css" />
<script>
Ext.onReady(function() {
var panel = new Ext.Panel({
layout:'hbox',
items: [{
html: 'I'm the panel 1',
flex: 3
},{
html: 'I'm the panel 2',
flex: 2
},{
html: 'I'm the panel 3',
flex: 1
},{
html: 'I'm the panel 4'
}]
});
panel.render(Ext.getBody());
});
</script>
</head>
<body>
</body>
</html>
Nel nostro esempio la larghezza/altezza di ciascun panel verrà calcolata in questo modo:
- se esistono figli senza la proprietà flex essi occuperanno solamente lo spazio da loro richiesto (nel nostro caso altezza o lunghezza del testo inserito);
- lo spazio rimanente verrà diviso proporzionalmente sulla base del valore di flex: quindi verranno sommate le cifre (3+2+1=6) e a ciascun Panel verrà assegnato una quantità di frazioni pari a quel valore (al pannello 1 verranno assegnati 3 sesti, al pannello 2 verranno assegnati 2 sesti e al pannello 3 verrà assegnato un sesto).
Layout minori
Ext.layout.ToolbarLayout (“toolbar”)
Layout utilizzato per costruire Ext.Toolbar. Non dovrebbe mai essere utilizzato esplicitamente ma deve essere gestito autonomamente dal framework.
Ext.layout.MenuLayout (“menu”)
Layout utilizzato per costruire Ext.menu.Menu. Non dovrebbe mai essere utilizzato esplicitamente ma deve essere gestito autonomamente dal framework.
Ext.layout.AutoLayout (“auto”)
Layout di default del framework che non offre nessuna regola particolare di composizione ma si basa sulle impostazioni base del browser. Rappresenta una semplice classe che funge esclusivamente da passthrough.