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

Ext JS: la classe Ext.Element per un DOM più comprensibile

Un componente fondamentale per la manipolazione del DOM
Un componente fondamentale per la manipolazione del DOM
Link copiato negli appunti

Tutti conoscono il difficile rapporto che intercorre tra Javascript e i componenti DOM presenti in una pagina HTML: differenze tra i vari browser, estendibilità limitata degli oggetti e assegnamento degli eventi base poco flessibile. All'interno di ExtJS, queste difficoltà vengono aggirate grazie alla classe Ext.Element che si occupa appunto di rappresentare un nodo HTML esponendone, sotto forma di metodi e di proprietà, tutte le funzionalità disponibili in un browser.

Per ottenere un oggetto Ext.Element si utilizza il metodo statico Ext.Element.get (o il suo alias Ext.get) passando come argomento l'id del nodo o eventualmente il riferimento all'oggetto HTMLElement. Una volta ottenuto l'oggetto è possibile modificarne la sua rappresentazione e il comportamento tramite un vasto insieme di proprietà e metodi esposti dal nostro framework.

Tra le proprietà l'unica degna di nota è dom la quale contiene un riferimento all'oggetto HTMLElement originale. Il grande insieme di metodi permette invece di:

  • modificare l'aspetto grafico dell'elemento (agendo sulle classi CSS o direttamente sulla proprietà da modificare);
  • ottenere informazioni sulla situazione attuale dell'elemento (posizionamento nella pagina o proprietà grafiche particolari);
  • navigare all'interno del documento partendo dall'elemento corrente (ottenere particolari tag children o risalire al tag parent);
  • alterare la struttura del documento partendo dall'elemento corrente (inserire nodi prima o dopo);
  • forzare la scatenazione di eventi (per esempio blur o focus);
  • assegnare e rimuovere callback su particolari eventi esposti dal browser (click, doubleclick, mouseover, mouseout, load,...);
  • modificare il contenuto HTML dell'elemento.

Tutti i metodi esposti sono particolarmente intuitivi e comprensibili. La miglior risorsa per recuperare eventuali informazioni riguardo al funzionamento di particolari funzioni rimane la documentazione ufficiale disponibile su questa pagina.

Ecco il primo esempio dell'articolo su come modificare alcuni comportamenti di elementi della pagina:

<html>
<head>
<script src="../ext-base.js" type="text/javascript"></script>
<script src="../ext-all-debug.js" type="text/javascript"></script>
<link rel="stylesheet" href="../css/ext-all.css"></link>
<script type="text/javascript">
Ext.onReady(function() {
	var div1 = Ext.get("div01");
	div1.setStyle({
		backgroundColor: "red", width: 300,
		height: 100
	});
	div1.update("contenuto dinamico");
	var div2 = div1.next();
	div2.setHeight(100);
	div2.setWidth(500);
	div2.setStyle("backgroundColor","blue");
	alert(div2.getTop());
	div2.hover(function() {
		div1.hide();
	}, function() {
		div1.show();
	});
});
</script>
</head>
<body>
<div id='div01'></div>
<div></div>
</body>
</html>

Il codice è abbastanza auto-esplicativo per cui non ci soffermeremo ulteriormente.

Aggiungere elementi alla pagina...

L'esempio permette di modificare elementi DOM già presenti all'interno del nostro HTML. Ma come dobbiamo comportarci nel caso volessimo aggiungere nuovi nodi tramite Javascript? ExtJS ci viene incontro con alcuni metodi della classe Ext.Element e con una nuova classe statica che faciliterà non di poco la creazione di HTML: Ext.DomHelper.

Questa nuova classe permette di creare frammenti di HTML partendo sia da una stringa che da un oggetto Javascript composto da particolari proprietà.

...utilizzando una stringa HTML

Il primo metodo permette di creare nuovi nodi HTML alla pagina utilizzando stringhe; basta invocare il metodo statico Ext.DomHelper.append passando come primo parametro l'id del nodo container e come secondo parametro la stringa HTML (esempio):

<html>
<head>
<script src="../ext-base.js" type="text/javascript"></script>
<script src="../ext-all-debug.js" type="text/javascript"></script>
<link rel="stylesheet" href="../css/ext-all.css"></link>
<script type="text/javascript">
Ext.onReady(function() {
	Ext.DomHelper.append("div01", "<span id='span01'>ciao</span>");
	Ext.DomHelper.append("span01", "<a href='#' class='myLink'>Link</a>");
});
</script>
</head>
<body>
<div id='div01'></div>
</body>
</html>

... utilizzando un oggetto Javascript

Il secondo metodo è sicuramente più flessibile e permette di costruire un frammento HTML partendo da un oggetto Javascript anche complesso e indentato. Le proprietà dell'oggetto creato verranno trasformate in attributi HTML. Le uniche proprietà particolari sono:

  • tag (identifica il tipo di nodo);
  • children o cn (array contenente eventuali tag children);
  • cls (classe css per l'elemento);
  • html (stringa HTML da appendere all'elemento).

Ecco ora l'esempio di prima ">riscritto con questa nuova tecnica:

<html>
<head>
<script src="../ext-base.js" type="text/javascript"></script>
<script src="../ext-all-debug.js" type="text/javascript"></script>
<link rel="stylesheet" href="../css/ext-all.css"></link>
<script type="text/javascript">
Ext.onReady(function() {
	Ext.DomHelper.append("div01", {
		tag: "span",
		id: "span01",
		children: ["ciao", {
			tag: "a",
			href: "#",
			html: "Link",
			cls: "myLink"
		}]
	});
});
</script>
</head>
<body>
<div id='div01'></div>
</body>
</html>

Il pattern flyweight

L'utilizzo del metodo Ext.Element.get permette di referenziare, a partire da un id, una variabile con un elemento della pagina. Se all'interno della nostra applicazione avessimo però la necessita di ottenere molti elementi, utilizzando questo metodo rischieremmo di occupare, spesso inutilmente, una grandissima quantità di memoria per referenziare ogni volta il nuovo elemento recuperato dal DOM.

Per risolvere questo problema di performance, ExtJS mette a disposizione un oggetto Element condiviso tra i vari moduli dell'applicazione, utilizzabile tutte le volte che ci serve modificare un nodo della pagina senza però doverne salvare il riferimento. Utilizzando Ext.Element.fly (o il suo alias Ext.fly) possiamo far riferimento ad un particolare nodo senza però tenerne traccia in memoria.

Per approfondire questo utile e utilizzatissimo design pattern suggerisco la lettura del breve articolo su Wikipedia.

Le animazioni

Tutti i metodi di Ext.Element che manipolano la rappresentazione grafica dell'oggetto HTML non utilizzano un'animazione particolare ma modificano direttamente la proprietà agendo sulle relative proprietà esposte dal browser. Alcune metodi di manipolazione presentano un parametro opzionale animate che deve essere passato come ultimo e che permette di configurare l'eventuale animazione che vogliamo mostrare all'utente. Questo parametro può essere rappresentato da un boolean (nel caso true) per utilizzare un'animazione di default o da un oggetto Javascript nel caso volessimo personalizzare l'effetto. Le proprietà per modificare il comportamento dell'animazione sono quattro:

  • effect (default easeOut): stringa che identifica la tipologia di effetto da applicare utilizzabile da un set di tipi possibili (l'ultima versione di ExtJS supporta backBot, backIn, backOut, bouceBoth, bounceOut, bounceIn, easeBoth, easeBothStrong, easeIn, easeInStrong, easeNone, easeOut, easeOutStrong, elasticBoth, elasticIn, elasticOut);
  • duration (default 0.35): secondi o frazioni di secondi che identificano la durata dell'animazione (più il valore è alto, più l'animazione sarà lenta);
  • callback (default undefined): funzione che verrà invocata automaticamente una volta che l'animazione verrà completata;
  • scope (default Ext.Element corrente): eventuale scope di esecuzione della funzione di callback.

Rivediamo ora l'esempio precedente introducendo alcune componenti animate:

<html>
<head>
<script src="../ext-base.js" type="text/javascript"></script>
<script src="../ext-all-debug.js" type="text/javascript"></script>
<link rel="stylesheet" href="../css/ext-all.css"></link>
<script type="text/javascript">
Ext.onReady(function() {
	var div1 = Ext.get("div01");
	div1.setStyle({
		backgroundColor: "red",
		width: 300,
		height: 100
	});
	div1.update("contenuto dinamico");
	var div2 = div1.next();
	div2.setHeight(100);
	div2.setWidth(500);
	div2.setStyle("backgroundColor","blue", true);
	div2.hover(function() {
		div1.setWidth(500, {
			duration: .50,
			callback: function() {
				Ext.fly("console").update("W le animazioni"); //scrivo in console quando l'animazione è terminata
			}
		});
	}, function() {
		div1.setWidth(300,  {
			duration: 1, //piu lento
			easing: "elasticBoth", //cambio tipologia di animazione
			callback: function() {
				Ext.fly("console").update("");
			}
		});
	});
});
</script>
</head>
<body>
<div id='div01'></div>
<div></div>
<div id='console'></div>
</body>
</html>

Oltre ai metodi core esposti da Ext.Element, ciascun oggetto di questa classe eredita anche un insieme di metodi dall'oggetto Ext.Fx. Questi nuovi metodi permettono per esempio di interrompere (o fermare temporaneamente) l'animazione, creare un effetto di highlight al termine dell'animazione o sincronizzare la coda degli effetti. Come al solito, il miglior modo per approfondire l'argomento rimane la lettura della guida ufficiale.

Ext.CompositeElement e Ext.CompositeElementLite

L'ultimo strumento esposto dal framework per manipolare la pagina è rappresentato dalle due classi Ext.CompositeElement e Ext.CompositeElementLite. La differenza tra le due classi è lieve: il componente lite semplicemente presenta un numero di metodi inferiori e deve essere utilizzato a meno di richieste particolari che necessitano uno dei metodi presenti in Ext.CompositeElement.

Un CompositeElement rappresenta un elenco di Ext.Element che appartengono ad uno stesso gruppo concettuale e che devono essere trattati come un'unica entità. Grazie ad essi possiamo invocare qualsiasi metodo esposto da Ext.Element e Ext.Fx non su un unico oggetto ma su una collezione di Ext.Element. Oltre a questi metodi “ereditati” queste due classi presentano metodi per alterare la composizione interna degli elementi dando la possibilità al programmatore di aggiungere e rimuovere elementi.

Il miglior modo per ottenere un CompositeElement è l'utilizzo del metodo statico Ext.Element.select (o il suo alias Ext.select) passando come parametro principale un selettore CSS sotto forma di stringa.

Ecco un breve esempio chiarificatore:

<html>
<head>
<script src="../ext-base.js" type="text/javascript"></script>
<script src="../ext-all-debug.js" type="text/javascript"></script>
<link rel="stylesheet" href="../css/ext-all.css"></link>
<script type="text/javascript">
Ext.onReady(function() {
	var allComponent = Ext.select("div");
	allComponent.setWidth(400);
	allComponent.setHeight(100);
	allComponent.hover(function() {
		//nel caso di CompositeElement lo scope non è l'Ext.Element ma l'oggetto HTML
		//usiamo Ext.fly per ottenere l'Ext.Element
		Ext.fly(this).setWidth(700, true);
	}, function() {
		Ext.fly(this).setWidth(400, true);
	});
	//utilizzo la direttiva even per ottenere i div "pari"
	Ext.select("div:even").setStyle("backgroundColor","lightblue");
	//utilizzo la direttiva odd per ottenere i div "dispari"
	Ext.select("div:odd").setStyle("backgroundColor","darkblue");
});
</script>
</head>
<body>
<div></div>
<div></div>
<div></div>
<div></div>
</body>

Grazie ai CompositeElement è possibile ottenere effetti complessi con davvero poche righe di codice.

Per approfondire il meccanismo di selezione di elementi DOM partendo da un selettore CSS e scoprire tutti gli strumenti offerti consiglio la lettura della documentazione della classe Ext.DomQuery.

Tutti gli esempi visti nell'articolo sono disponibili per il download.

Conclusioni

Nonostante l'argomento trattato in questo articolo sia ancora abbastanza astratto per un framework ad alto livello come ExtJS, è necessario, prima di approfondire componenti grafici più complessi, comprendere i meccanismi interni per sapere dove intervenire sia per un utilizzo base della libreria sia per eventuali estensioni che potrebbero essere necessarie durante lo sviluppo di un processo di una certa entità.

Nel prossimo articolo introdurremo un concetto più ad alto livello che permetterà di definire template riutilizzabili nelle nostre applicazioni.

Ti consigliamo anche