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

Analisi della classe Ext.util.Observable

Gestione avanzata degli eventi in Ext.js
Gestione avanzata degli eventi in Ext.js
Link copiato negli appunti

La classe Ext.util.Observable rappresenta la classe principale delle API di Ext.js: moltissime altre classi infatti la estendono acquisendo in questo modo la possibilità di istanziarsi come oggetti appunto observable (traducibili in osservabile o, forse meglio, in ascoltabile).

Un oggetto observable presenta la possibilità di integrarsi con altri oggetti tramite il concetto di evento. Questo concetto ultimamente sta ottenendo sempre più consensi nel mondo della programmazione tant'è che si è dato un nome a questa tipologia di sviluppo software: Event-oriented programming.

Event-oriented programming

Quando si realizza un'applicazione di una certa complessità, è buona norma quella di scomporre i problemi complessi in tanti sotto processi più piccoli e facilmente gestibili. Una volta realizzati i diversi componenti, però, è necessario che scambino tra di loro le informazioni per poter realmente integrarli in una applicazione più grande. La event-oriented programming è un tipo di programmazione che utilizza il concetto di evento proprio per permettere la comunicazione tra i vari elementi.

Un oggetto che espone determinati eventi rappresenta un oggetto che presenta diversi punti aggancio verso il mondo esterno e quindi verso altri oggetti presenti nella applicazione. Immaginiamo un'applicazione composta semplicemente da un menu laterale con diverse voci e un pannello centrale che mostra dati in base alla voce di menu selezionata. L'oggetto menu e l'oggetto pannelloPrincipale saranno completamente slegati tra di loro in quanto ognuno presenta comportamenti propri che non hanno nulla a che fare con il resto dell'applicazione. Questi due componenti devono però poter comunicare in quanto nel caso in cui l'utente dovesse cliccare su una voce del menu, egli si aspetterebbe che il contenuto del pannello principale cambi. Questo significa che l'oggetto menu, in qualche modo, ha la necessità di comunicare con l'oggetto pannelloPrincipale.



È proprio in questo caso che intervengono gli eventi. Grazie a loro è infatti possibile definire determinati comportamenti per ciascun evento esposto. Nel nostro caso procedente all'evento click sull'oggetto menu avremmo assegnato il metodo show dell'oggetto pannelloPrincipale. Una funzione associata ad un determinato evento prende il nome di listener in quanto è come se fosse una funzione "in ascolto" verso lo scatenarsi di un determinato evento.

La classe Ext.util.Observable e la gestione degli eventi in ExtJS

All'interno di Ext.js tutta la parte relativa agli eventi e alle relative funzioni listeners viene implementata all'interno appunto della classe Ext.util.Observable.

Esistono due alternative per assegnare ad un evento di un oggetto (gerarchicamente sottoposto a Ext.util.Observable) delle funzioni listeners. Ecco due esempi nei quali verrà assegnata una funzione per mostrare un avviso una volta che i pannelli vengono renderizzati nella pagina (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() {
	var renderCallback = function() {
		alert("Panel is now rendered");
	}
	var panel = new Ext.Panel({
		html: "Contenuto del pannello",
		title: "Titolo del pannello",
		width: 300,
		height: 400,
		listeners: {
			render: renderCallback
		}
	});
	panel.render("div01");
	var panel2 = new Ext.Panel({
		html: "Contenuto del pannello 2",
		title: "Titolo del pannello 2",
		width: 500,
		height: 200,
	});
	panel2.on("render", renderCallback);
	panel2.render("div01");
});
</script>
</head>
<body>
<div id='div01'></div>
</body>
</html>

L'unica differenza tra i due approcci è quella che utilizzando il metodo on (che non è nient'altro che un alias di addListener) è possibile assegnare più funzioni listeners allo stesso evento, cosa non possibile per quanto riguarda la proprietà listeners in fase di creazione del componente.

Controllo maggiore sui listeners

Nel momento dell'assegnazione di un listener, oltre al nome dell'evento e della funzione di callback, è possibile specificare ulteriori parametri spesso molto utili per una gestione più complessa dell'evento:

  • scope (Object): utile per eseguire la funzione listener in un contesto diverso da quello dell'oggetto "ricevente"; viene spesso utilizzata quando si ragiona in ottica object-oriented;
  • delay (Number): per ritardare l'invocazione di un numero di millisecondi;
  • single (Boolean): per eseguire la funzione solo una volta e rimuovere in automatico il listener al termine dell'esecuzione;
  • buffer (Integer): per impostare una serie di invocazioni automatiche della funzione una volta scatenato l'evento.

Parametri

La classe Ext.util.Observable non si occupa solamente di invocare le funzioni listeners, ma permette di ottenere, all'interno di esse, eventuali parametri che possono essere utili soprattutto perché spesso le funzioni listeners non hanno accesso all'oggetto originario. Per esempio l'evento utilizzato (render) negli esempi di prima scatena il listener ad esso associato passandogli come parametro il pannello stesso. È possibile quindi migliorare il precedente listener in questo modo (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() {
	var renderCallback = function() {
		alert("Panel: " + panel.initialConfig.title + " rendered!");
	}
	var panel = new Ext.Panel({
		html: "Contenuto del pannello",
		title: "Titolo del pannello",
		width: 300,
		height: 400,
		listeners: {
			render: renderCallback
		}
	});
	panel.render("div01");
	var panel2 = new Ext.Panel({
		html: "Contenuto del pannello 2",
		title: "Titolo del pannello 2",
		width: 500,
		height: 200,
	});
	panel2.on("render", renderCallback);
	panel2.render("div01");
});
</script>
</head>
<body>
<div id='div01'></div>
</body>
</html>

Il miglior modo per conoscere quali sono i parametri passati ai listeners per ciascun evento è l'utilizzo delle API ufficiali di ExtJS.

Delegazione e bubbling di eventi

La delegazione e il bubbling sono due caratteristiche della programmazione ad eventi presente in ExtJS che facilitano notevolmente l'organizzazione architetturale e logica dell'applicazione.

Con delegazione si intende la possibilità di forzare la scatenazione di eventi di un particolare componente anche se gli stessi derivano da un altro oggetto. Questo comportamento è possibile grazie al metodo relayEvents. Grazie ad esso è possibile creare componenti complessi che incapsulino altri componenti e assegnare al solo componente esterno la possibilità di interfacciarsi con il resto dell'applicazione mantenendo di fatto “privati” i componenti più interni.

Con bubbling si intende invece la possibilità di un evento di risalire autonomamente la catena gerarchica dei componenti permettendo all'utente di mettersi in ascolto solamente sul più esterno senza preoccuparsi degli elementi interni. Questo comportamento è possibile grazie al metodo enableBubble. Grazie al bubbling lo sviluppatore potrà mettersi in ascolto solo sul componente gerarchicamente più elevato e questo verrà scatenato anche da eventuali componenti di un livello inferiore.

Estendere una classe Observable

Ovviamente il modello utilizzato da ExtJS per la gestione degli eventi non presenta funzionalità solo dal punto di vista dell'utilizzatore ma permette anche di definire eventi personalizzati all'interno delle nostre classi che estendono Ext.util.Observable. Le API di ExtJS presentano due metodi, addEvents e fireEvent, che permettono appunto di aggiungere e invocare determinati eventi, controllando anche eventuali parametri da passare ai possibili listener.

Il metodo addEvent accetta oggetto contenente i nomi degli eventi e li aggiunge all'elenco degli eventi gestiti da una classe. Questo metodo deve essere invocato in fase di creazione dell'oggetto in modo da rendere disponibili gli eventi il prima possibile.

Una volta aggiunti gli eventi, è possibile richiamarli e scatenarli all'interno della classe utilizzando fireEvent al quale è possibile comunicare, oltre alla stringa identificatrice del nome dell'evento, eventuali altri parametri che saranno automaticamente forniti alle funzioni in ascolto.

Come al solito il miglior strumento per comprendere è un esempio concreto:

<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">
var Person = Ext.extend(Ext.util.Observable, {
  constructor: function(name) {
    this.name = name;
    this.addEvents({
      birth: true,
      married: true
    });
    Person.superclass.constructor.call(this);
  },
  meets: function(anotherPerson) {
    if(this.likes(anotherPerson) && anotherPerson.likes(this)) {
      this.fireEvent("married", this, anotherPerson);
    }
  },
  likes: function(anotherPerson) {
    return Math.random()>0.5;
  }
});
var j = new Person("John");
var s = new Person("Sue");
var listener = function(person, anotherPerson) {
  alert(person.name + " has just get married with " + anotherPerson.name);
}
j.on("married", listener);
j.meets(s);
</script>
</head>
<body>
</body>
</html>

In questo esempio abbastanza “esotico” abbiamo definito la classe Person come sottoclasse di Ext.util.Observable utilizzando il metodo Ext.extend (che introdurremo nei prossimi articoli). Questa classe espone due eventi: birth e married. All'interno della funzione meets, grazie al metodo fireEvent, scateniamo uno di questi due eventi (married nel caso) passando come parametri opzionali la persona corrente e la persona incontrata.

Per utilizzare la classe Person istanziamo due persone (j e s) e prima di farle incontrare definiamo la funzione listener che verrà invocata nel momento in cui John e Sue abbiano un colpo di fulmine e decidano di sposarsi.

Ti consigliamo anche