[nextpage title=”Benvenuti”] jQuery stà diventando rapidamente uno strumento che ogni sviluppatore web di interfacce dovrebbe conoscere. Lo scopo di questo libro è di fornire una panoramica della biblioteca, in modo che quando hai finito di leggere, sarai in grado di eseguire operazioni di base utilizzando jQuery e avere una solida base per un apprendimento ulteriore. Il libro è stato progettato per essere utilizzato come materiale in un’aula di classe, ma può anche essere utile per lo studio individuale.

Il metodo di lavoro è il seguente: in primo luogo, si dedicherà del tempo per capire un concetto per poi fare un esercizio correlato. Alcuni degli esercizi possono anche essere banali, mentre altre non lo sono. L’obiettivo è quello di imparare a risolvere in maniera semplice, ciò che normalmente si risolverebbe con jQuery. Soluzioni per tutti gli esercizi sono inclusi nello stesso materiale d’apprendimento.

Ottenere il materiale didattico
⤽
Il materiale didattico e il codice sorgente degli esempi citati nel libro sono ospitati sulla repository GitHub . Da qui è possibile scaricare un file in formato .zip o .tar con il codice per l’uso su un server web.
Software
⤽
Per lavorare con i contenuti del libro, saranno necessari i seguenti strumenti:

  • Firefox Browser Web
  • L’estensione Firebug per Firefox
  • Un editor di testo (come Notepad + + per Windows, gedit / Kate TextMate per Linux o Mac OS X)
  • Per le sezioni su Ajax: un server locale (come WAMP o MAMP) o un client FTP/SSH per accedere a un server remoto.
Aggiungere JavaScript in una Pagina
⤽
Ci sono due modi per inserire del codice JavaScript all’interno di una pagina: scrivendo il codice nella stessa linea (in lingua inglese inline) o tramite un file esterno utilizzando il tag script. L’ordine in cui s’include il codice è importante: un codice che dipende da un altro dovrebbe essere incluso dopo di quello che fa riferimento (Esempio: Se la funzione B dipende dalla A, l’ordine deve essere A, B e non B, A).

Per migliorare le prestazioni della pagina, il codice JavaScript deve essere incluso alla fine del HTML. Inoltre, quando si lavora in un ambiente di produzione con più file JavaScript, devono essere combinati in un unico file.

1.1: Esempio di codice JavaScript in linea
⤽
Copia codice

<script>
console.log('ciao');
</script>
1.2: Esempio d'inclusione di un file esterno JavaScript
⤽
Copia codice

<script src='/js/jquery.js'></script>
Debugging del codice JavaScript
⤽
L’uso di uno strumento di debug è essenziale per lavorare con JavaScript. Firefox fornisce un debugger tramite l’estensione Firebug, mentre Safari e Chrome hanno un sistema integrato.

Ogni debugger offre:

  • Un editore multi-line per sperimentare con JavaScript;
  • Un ispettore per rivedere il codice generato nella pagina;
  • Un visualizzazione di rete o risorse, di esaminare le richieste che vengono fatte.

Quando si scrive codice JavaScript, è possibile utilizzare uno dei seguenti metodi per inviare messaggi alla console del debugger:

  • console.log() per inviare e registrare messaggi generali;
  • console.dir() per registrare un oggetto e visualizzarne le proprietà;
  • console.warn() per registrare messaggi di alert;
  • console.error() per registrare i messaggi di errore;

Esistono altri metodi per utilizzarli dalla console, ma questi possono variare a seconda del browser. La console offre inoltre la possibilità di impostare punti d’interruzione e osservare le espressioni nel codice per facilitare il debug.

Esercizi
⤽
La maggior parte dei capitoli concludono con uno o più esercizi. In alcuni si potrà lavorare direttamente con Firebug, in altri sarà necessario scrivere il codice JavaScript dopo d’includere la libreria jQuery nel documento.

Anche così, per completare alcuni esercizi, sarà necessario consultare la documentazione ufficiale di jQuery. Imparare a trovare le risposte è una parte importante del processo di apprendimento.

Ecco alcuni suggerimenti per affrontare i problemi:

  • Per prima cosa, assicurarsi di aver compreso il problema si sta tentando di risolvere.
  • Poi, sapere a quali oggetti si dovranno accedere per risolvere il problema e decidere come accedervi. È possibile utilizzare Firebug per verificare se si sta ottenendo il risultato atteso.
  • Infine, scoprire cosa deve essere fatto con questi elementi per risolvere il problema. Può essere utile prima di iniziare, scrivere commenti che spiega cosa dovrà fare.

Non abbiate paura di sbagliare. E neanche provare, al primo tentativo, di scrivere un codice perfetto. Commettere errori e sperimentare soluzioni fa parte del processo di apprendimento e aiuterà a essere uno sviluppatore migliore. È possibile trovare nella cartella /solutions esempi di soluzioni agli esercizi del libro.

Convenzioni utilizzate nel libro
⤽
I metodi che possono essere chiamati dall’oggetto jQuery, faranno riferimento come $.fn.nomreDelMetodo. I metodi che esistono nello spazio dei nomi (namespace in inglese) di jQuery, ma che non possono essere chiamati dall’oggetto jQuery, faranno riferimento come $.nomeDelMetodo. Se questo non significa molto per ora, non si preoccupi – sarà più chiaronel procedere del libro.
1.3: Un codice di esempio
⤽
Copia codice

// Il codice di esempio apparirà in questo modo

I richiami appariranno in questo modo.

Le note su qualche tema appariranno di questa forma.

Note sulla traduzione
⤽
  • Perché il materiale ha lo scopo di apprendimento e di insegnamento, è tradotto in italiano formale (voi).
  • Molti termini tecnici sono nominati nella sua traduzione in italiano. Tuttavia, per tenere riferimento, si spiega anche come si chiamano in inglese.
  • Gli esempi e le soluzioni agli esercizi non sono completamente tradotti. Questo perché, quando si lavora su un progetto reale, il codice trovato su altri siti potrebbe essere scritto in inglese. Eppure, i commenti incorporati nei codici sono stati tradotti così come altri testi particolari per facilitare la comprensione.
Materiale di riferimento
⤽
Ci sono una gran quantità di articoli che trattano alcuni aspetti di jQuery. Alcuni sono eccellenti, mentre altri, francamente, sono erronei. Quando si legga un articolo su jQuery, accertarsi che tratti la stessa versione della libreria in uso, e resistere alla tentazione di copiare e incollare il codice – prendere tempo per capirlo.

A continuazione ci sono una serie di eccellenti risorse da utilizzare durante l’apprendimento. La più importante di tutte è il codice sorgente di jQuery, che contiene (in formato non compresso) una documentazione completa attraverso i commenti. La biblioteca non è una scatola nera – la sua comprensione aumenterà in modo esponenziale ogni volta che la si rivede – ed è altamente consigliabile memorizzare il link nel vostro browser preferito per averla come guida di riferimento.

[nextpage title=”Concetti di base di JavaScript”] Introduzione
⤽
jQuery è scritto in JavaScript, un linguaggio di programmazione molto ricco ed espressivo.

Il capitolo si rivolge a chi non conosce il linguaggio, e copre i concetti di base e problemi comuni che possono sorgere quando si lavora con esso. Inoltre, la sezione può essere utile a chi utilizza altri linguaggi di programmazione per capire le peculiarità di JavaScript.

Se siete interessati a saperne di più sul linguaggio, si può leggere il libro JavaScript: The Good Parts che Douglas Crockford ha scritto.

Sintassi di base
⤽
Comprendere dichiarazioni, nomi di variabile, spaziatura, e altre sintassi di base JavaScript
2.1: Dichiarazione semplice di una variabile
⤽
Copia codice

var foo = 'ciao mondo';
2.2: Gli spazi non hanno alcun valore al di fuori delle virgolette
⤽
Copia codice

var foo =     'ciao mondo';
2.3: Le parentesi indicano la priorità
⤽
Copia codice

2 * 3 + 5;    // ritorna 11; il prodotto si esegue prima
2 * (3 + 5);  // ritorna 16; per le parentesi, la somma si esegue prima
2.4: La tabulazione migliora la lettura del codice, ma non ha un significato speciale
⤽
Copia codice

var foo = function() {
    console.log('ciao');
};
Operatori
⤽
Operatori di base
⤽
Gli operatori di base permettono la manipolazione di valori.
2.5: Concatenazione
⤽
Copia codice

var foo = 'ciao';
var bar = 'mondo';
console.log(foo + ' ' + bar); // 'ciao mondo'
2.6: Moltiplicazione e divisione
⤽
Copia codice

2 * 3;
2 / 3;
2.7: Incremento e decremento
⤽
Copia codice

var i = 1;
var j = ++i;  // incremento anticipato: j è uguale a 2; i è uguale a 2
var k = i++;  // incremento posticipato: k è uguale a 2; i è uguale a 3
Lavorare con i numeri e le stringhe
⤽
In JavaScript, quando si lavora con i numeri e con le stringhe può causare risultati imprevisti.
2.8: Somma vs. concatenazione
⤽
Copia codice

var foo = 1;
var bar = '2';
console.log(foo + bar);  // errore: la console di debug mostra 12
2.9: Forzare una stringa ad agire come un numero
⤽
Copia codice

var foo = 1;
var bar = '2';
// il costruttore 'Number' obbliga alla
// stringa di comportarsi come un numero
console.log(foo + Number(bar)); // la console di debug mostra 3
Il costruttore Number, quando viene chiamato come una funzione (come nell’esempio) obbliga al suo argomento a comportarsi come un numero. È inoltre possibile utilizzare l’operatore somma unaria, che ritorna lo stesso risultato:
2.10: Forzare una stringa per agire come un numero (somma unaria)
⤽
Copia codice

console.log(foo + +bar);
Operatori Logici
⤽
Gli operatori logici permettono valutare una serie di operandi utilizzando operazioni AND e OR.
2.11: Operatori Logici AND e OR
⤽
Copia codice

var foo = 1;
var bar = 0;
var baz = 2;
foo || bar;   // ritorna 1, il quale è vero (true)
bar || foo;   // ritorna 1, il quale è vero (true)
foo && bar;   // ritorna 0, il quale è falso (false)
foo && baz;   // ritorna 2, il quale è vero (true)
baz && foo;   // ritorna 1, il quale è vero (true)
L’operatore || (OR logico) restituisce il valore del primo operando, se questo è vero, altrimenti restituisce il valore del secondo operando. Se entrambi gli operandi sono falsi restituisce false (falso). L’operatore && (AND logico) restituisce il valore del primo operando se questo è falso, altrimenti restituisce il valore del secondo operando. Quando entrambi i valori sono veri ritorna vero (true), altrimenti restituisce falso.

È possibile consultare la sezione “Elementi Vero e Falso” per ulteriori dettagli su quali valori vengono valutati come true e quali vengono valutati come false.

Talvolta si può notare che alcuni sviluppatori utilizzino questa logica per il controllo del flusso invece di utilizzare la dichiarazione if. Per Esempio:

Copia codice

// fare qualcosa con foo se foo è vero
foo && doSomething(foo);
// stabilire bar uguale a baz se baz è vero;
// caso contrario, stabilire bar uguale al
// valore di createBar()
var bar = baz || createBar();
Questo stile dichiarazione è molto elegante e concisa, ma può essere difficile da leggere (specialmente per i principianti). È per questo si esplicita, per riconoscerlo durante la lettura del codice. Tuttavia, il suo uso non è raccomandato a meno che non si ha dimestichezza con il concetto e il comportamento.

Operatori di Confronto
⤽
Gli operatori di confronto consentono di verificare se certi valori sono equivalenti o identiche.
2.12: Operatori di confronto
⤽
Copia codice

var foo = 1;
var bar = 0;
var baz = '1';
var bim = 2;
foo == bar;   // ritorna false
foo != bar;   // ritorna true
foo == baz;   // ritorna true; fare attenzione!
foo === baz;             // ritorna false
foo !== baz;             // ritorna true
foo === parseInt(baz);   // ritorna true
foo > bim;    // ritorna false
bim > baz;    // ritorna true
foo <= baz;   // ritorna true
Codice Condizionale
⤽
A volte si desidera eseguire un blocco di codice in determinate condizioni. Le strutture di controllo del flusso – attraverso l’uso di istruzioni if ??ed else permettono di farlo.
2.13: Controllo del flusso
⤽
Copia codice

var foo = true;
var bar = false;
if (bar) {
    // questo codice non verrà mai eseguito
    console.log('ciao!');
}
if (bar) {
    // questo codice non si eseguirà
} else {
    if (foo) {
        // questo codice si eseguirà
    } else {
        // si eseguirà se foo e bar sono falsi (false)
    }
}

In una linea singola, quando si scrive un’istruzione if, le parentesi non sono strettamente necessari, ma è raccomandato in quanto rende il codice molto più leggibile.

È necessario essere consapevoli di non definire funzioni con lo stesso nome più volte all’interno di istruzioni if/else, giacché si potrebbe ottenere risultati inaspettati.

Elementi Veri e Falsi
⤽
Per controllare il flusso correttamente, è importante capire quali tipi di valori sono “veri” e che “false”. A volte, alcuni valori possino sembrare una cosa, ma finiscono per essere un’altra.
2.14: Valori che ritornano il vero true
⤽
Copia codice

'0';
'qualunque stringa';
[];  // un array vuoto
{};  // un oggetto vuoto
1;   // qualsiasi numero diverso da zero
2.15: Valori che ritornano il falso false
⤽
Copia codice

0;
'';  // una stringa vuota
NaN; // la variabile JavaScript "not-a-number" (non è un numero)
null; // un valore nullo
undefined;  // // fare attenzione -- (undefined) può essere ridefinito
Variabili condizionali utilizzando l'operatore ternario
⤽
A volte si desidera impostare il valore di una variabile in funzione a una certa condizione. Per farlo si può utilizzare una dichiarazione if/else, ma in molti casi è più conveniente usare l’operatore ternario. [Definizione:. L’operatore ternario valuta una condizione, se la condizione è vera, restituisce un certo valore, altrimenti restituisce un valore diverso] 2.16: L'operatore ternario
⤽
L’operatore ternario può essere utilizzato senza restituire un valore alla variabile, ma questo uso è generalmente sconsigliato.
Dichiarazione Switch
⤽
Invece di usare una serie di istruzioni if/else/else if/else, a volte può essere utile usare l’istruzione switch. [Definizione: un’istruzione Switch valuta il valore di una variabile o espressione ed esegue diferenti blocchi di codice a seconda di quel valore.] 2.17: Una dichiarazione Switch
⤽
Copia codice

switch (foo) {
    case 'bar':
        alert('il valore è bar');
    break;
    case 'baz':
        alert('il valore è baz');
    break;
    default:
        alert('impostazione predefinita, questo codice verrà eseguito');
    break;
}
Istruzioni switch sono poco utilizzati in JavaScript, perché lo stesso comportamento può essere ottenuto attraverso la creazione di un oggetto, che ha più potenzialità perché si può riutilizzare, usarlo per i test, e così via.
Per Esempio:
⤽
Copia codice

var stuffToDo = {
    'bar' : function() {
        alert('il valore è bar');
    },
    'baz' : function() {
        alert('il valore è baz');
    },
    'default' : function() {
        alert('impostazione predefinita, questo codice verrà eseguito');
    }
};
if (stuffToDo[foo]) {
    stuffToDo[foo]();
} else {
    stuffToDo['default']();
}
Più avanti si tratterà il concetto di oggetti.
Cicli
⤽
I cicli (loops in inglese) permettono eseguire un blocco di codice un certo numero di volte.
2.18: Cicli
⤽
Copia codice

// mostra nella console 'tentativo 0', 'tentativo 1', ..., 'tentativo 4'
for (var i=0; i<5; i++) {
    console.log('tentativo ' + i);
}
Si noti che nell’esempio si utilizza la parola var prima della variabile i, questo significa che detta variabile è all’interno della sua portata, o ambito, (in inglese scope) del ciclo. Più avanti in questo capitolo si esaminerà in modo approfondito il concetto di portata.
Cicli utilizzando FOR
⤽
Un ciclo utilizzando for si compone da quattro Stati e ha la seguente struttura:
Copia codice

for ([espressioneIniziale]; [condizione]; [incrementoDellaEspressione])
 [corpoCiclo]
Lo stato espressioneIniziale viene eseguito una solavolta, prima che il ciclo cominci. Questo dà la possibilità di preparare o di dichiarare le variabili.

Lo stato condizione viene eseguita prima di ogni iterazione, e restituisce un valore che decide se il ciclo deve continuare oppure no. Se lo stato condizionale valuta un valore come falso il ciclo si interrompe.

Lo stato incrementoDellaEspressione viene eseguito alla fine di ogni ripetizione e offre l’opportunità di modificare lo stato di variabili importanti. Di solito, questo stato comporta l’incremento o il decremento di un contatore.

Il corpoCiclo è il codice da eseguire in ogni iterazione del ciclo. In genere ci sono più istruzioni che devono essere eseguiti e così li avvolgono in un blocco ({…}).

Un tipico ciclo utilizzando for:
2.19: Un tipico ciclo utilizzando for

⤽
Copia codice

for (var i = 0, limit = 100; i < limit; i++) {
    // Questo blocco di codice viene eseguito 100 volte
    console.log('Attualmente a ' + i);
    // Nota: L'ultimo record da visualizzare
    // nella console sarà "Attualmente a 99"
}
Cicli utilizzando WHILE
⤽
Un ciclo utilizzando while è simile ad un’istruzione condizionale if, tranne che il corpo continuerà a funzionare fino a quando la condizione da valutare sia falsa.
Copia codice

for ([espressioneIniziale]; [condizione]; [incrementoDellaEspressione])
 [corpoCiclo]
Un típico bucle utilizzando while:
2.20: Un típico bucle utilizzando while
⤽
Copia codice

var i = 0;
while (i < 100) {
    // Questo blocco di codice verrà eseguito 100 volte
    console.log('Attualmente a ' + i);
    i++; // incrementa la variabile i
}
Si può notare che nell’esempio viene incrementato il contatore all’interno del corpo del ciclo, ma è anche possibile combinare la condizione e l’incremento, come illustrato di seguito:
2.21: Ciclo utilizzando while con la combinazione della condizione e l'incremento
⤽
Copia codice

var i = -1;
while (++i < 100) {
    // Questo blocco di codice verrà eseguito 100 volte
    console.log('Attualmente a ' + i);
}
la variabile i inizia a -1 e poi utilizza l’incremento anticipato (++i).
Cicli utilizzando do-while
⤽
Questo ciclo è come usare while, tranne che il corpo viene eseguito almeno una volta prima che la condizione venga valutata.
Copia codice

do [corpoCiclo] while ([condizione])
2.22: Un ciclo do-while
⤽
Copia codice

do {
    // Anche quando la condizione è falsa
    // il corpo del ciclo viene eseguito almeno una volta.
    alert('Ciao!');
} while (false);
Tali cicli sono abbastanza insoliti, perché raramente si ha bisogno di un ciclo che esegua un giro almeno una volta. In entrambi i casi si dovrebbe essere a conoscenza.
Break e Continue
⤽
Di solito, la fine dell’esecuzione di un ciclo coinciderà quando la condizione non continui a valutare un valore vero, tuttavia è anche possibile fermare un ciclo utilizzando l’istruzione break all’interno del corpo.
2.23: Fermare un ciclo con break
⤽
Copia codice

for (var i = 0; i < 10; i++) {
    if (qualcosa) {
        break;
    }
}
Può anche accadere che si desidera continuare il ciclo senza dover eseguire più dichiarazioni del corpo del ciclo. Questo può essere fatto utilizzando l’istruzione continue.
2.24: Saltare alla seguente iterazione di un ciclo
⤽
Copia codice

for (var i = 0; i < 10; i++) {
    if (qualcosa) {
        continue;
    }
    // La seguente dichiarazione sarà eseguita
    // se la condizione 'something' non si compie
    console.log('I have been reached');
}
Parole Riservate
⤽
JavaScript ha un numero di “parole riservate”, o parole che sono speciali all’interno dello stesso linguaggio. Si dovrebbe utilizzare queste parole quando si ha bisogno per il suo uso specifico.

  • abstract
  • boolean
  • break
  • byte
  • case
  • catch
  • char
  • class
  • const
  • continue
  • debugger
  • default
  • delete
  • do
  • double
  • else
  • enum
  • export
  • extends
  • final
  • finally
  • float
  • for
  • function
  • goto
  • if
  • implements
  • import
  • in
  • instanceof
  • int
  • interface
  • long
  • native
  • new
  • package
  • private
  • protected
  • public
  • return
  • short
  • static
  • super
  • switch
  • synchronized
  • this
  • throw
  • throws
  • transient
  • try
  • typeof
  • var
  • void
  • volatile
  • while
  • with
Vettori o Matrici
⤽
I vettori (in inglese arrays) sono liste di valori a indice zero (in inglese zero-index), cioè il primo elemento della matrice è l’indice 0. sono un modo conveniente per memorizzare un insieme di dati correlati (come stringhe), ma in realtà, un array può includere più tipi di dati, compresi altri array.
2.25: Un vettore semplice
⤽
Copia codice

var myArray = [ 'ciao', 'mondo' ];
2.26: Accedere agli elementi dell'array attraverso il suo indice
⤽
Copia codice

var myArray = [ 'ciao', 'mondo' ];
2.27: Ottenere il numero di elementi dell'array
⤽
Copia codice

var myArray = [ 'ciao', 'mondo' ];
console.log(myArray.length);   // mostra '2' nella console
2.28: Modificare il valore di un elemento di un array
⤽
Copia codice

var myArray = [ 'ciao', 'mondo' ];
myArray[1] = 'modificato';
Come mostrato nell’esempio “Modificare il valore di un elemento di un array” è possibile modificare il valore di un elemento di un array, in genere non è consigliabile.
2.29: Aggiungere elementi ad un array
⤽
Copia codice

var myArray = [ 'ciao', 'mondo' ];
myArray.push('nuovo');
2.30: Lavorando con gli array
⤽
Copia codice

var myArray = [ 'c', 'i', 'a', 'o' ];
var myString = myArray.join('');   // 'ciao'
var mySplit = myString.split('');  // [ 'c', 'i', 'a', 'o' ]
Oggetti
⤽
Gli oggetti sono elementi che possono contenere zero o più insiemi di coppie di nomi chiave e valori associati a tale oggetto. I nomi possono essere qualsiasi parola o numero valido. Il valore può essere qualsiasi tipo di valore: un numero, una stringa, un array, una funzione, anche un altro oggetto.

[Definizione: Quando uno dei valori di un oggetto è una funzione, è chiamato come metodo dell’oggetto.] In caso contrario, essi sono chiamati proprietà..

È interessante notare che in JavaScript, quasi tutto è un oggetto – array, funzioni, numeri, anche le stringhe – e tutti possiedono proprietà e metodi.

⤽
Copia codice

var myObject = {
    sayHello : function() {
        console.log('ciao');
    },
    myName : 'Rebecca'
};
myObject.sayHello();           // si chiama il metodo sayHello, che
                               // visualizza sulla console 'Ciao'
console.log(myObject.myName);  // si chiama la proprietà myName, che
                               // mostra 'Rebecca' nella console
Si noti che quando si creano oggetti letterali, il nome della proprietà può essere qualsiasi identificatore JavaScript, una stringa (racchiusa tra virgolette) o un numero:
Copia codice

var myObject = {
    validIdentifier: 123,
    'qualche stringa': 456,
    99999: 789
};

Gli oggetti letterali possono essere molto utile per l’organizzazione del codice, per maggiori informazioni potete leggere l’articolo (in inglese) Using Objects to Organize Your Code di Rebecca Murphey.

Funzioni
⤽
Le funzioni contengono blocchi di codice che viene eseguito ripetutamente. Alle stesse possono essere passati argomenti, e facoltativamente la funzione può restituire un valore.

Le funzioni possono essere creati in diversi modi:
2.32: Dichiarazione di una funzione

⤽
Copia codice

function foo() { /* fa qualcosa */ }
2.33: Dichiarare una funzione denominata
⤽
Copia codice

var foo = function() { /* fa qualcosa */ }
È preferibile il metodo della funzione denominata a causa di alcuni motivi tecnici profondo. Probabilmente troverete i due metodi quando si revisiona il codice JavaScript.
Utilizzo delle Funzioni
⤽
2.34: Una semplice funzione
⤽
Copia codice

var greet = function(person, greeting) {
    var text = greeting + ', ' + person;
    console.log(text);
};
greet('Rebecca', 'Ciao');
2.35: Una funzione che restituisce un valore
⤽
Copia codice

var greet = function(person, greeting) {
    var text = greeting + ', ' + person;
    return text;
};
console.log(greet('Rebecca','ciao'));
2.36: Una funzione che restituisce un'altra funzione
⤽
Copia codice

var greet = function(person, greeting) {
    var text = greeting + ', ' + person;
    return function() { console.log(text); };
};
var greeting = greet('Rebecca', 'Ciao');
greeting();
Funzioni Anonime Autoeseguilili
⤽
Un modello comune in JavaScript sono le funzioni anonime autoeseguibili. Questo modello consiste in creare un’espressione di funzione ed immediatamente eseguirla. Lo stesso è utile nei casi in cui non si vuole intervenire nei namespace globale, perché nessuna variabile dichiarata all’interno della funzione è visibile dall’esterno.
2.37: Una funzione anonima autoeseguibile
⤽
Copia codice

(function(){
    var foo = 'Ciao mondo';
})();
console.log(foo);   // indefinito (undefined)
Funzioni come Argomenti
⤽
In JavaScript, le funzioni sono “cittadini di prima classe” — possono essere assegnati alle variabili o passate ad altre funzioni come argomenti. In jQuery, passare funzioni come argomenti è una pratica molto comune.
2.38: Passare una funzione anonima come argomento
⤽
Copia codice

var myFn = function(fn) {
    var result = fn();
    console.log(result);
};
// mostra nella console 'Ciao mondo'
myFn(function() { return 'Ciao mondo'; });
2.39: Passare una chiamata di funzione come argomento
⤽
Copia codice

var myFn = function(fn) {
    var result = fn();
    console.log(result);
};
var myOtherFn = function() {
    return 'Ciao mondo';
};
// mostra nella console 'Ciao mondo'
myFn(myOtherFn);
Determinazione del tipo di variabile
⤽
JavaScript offre un modo per verificare il “tipo” (in inglese type) di una variabile. Tuttavia, il risultato può essere fonte di confusione – per Esempio, il tipo di array è un “object”.

Per ciò, è pratica comune usare l’operatore typeof quando si tratta di determinare il tipo di un valore specifico.
2.40: Determinare il tipo tra differenti variabili

⤽
Copia codice

var myFunction = function() {
    console.log('ciao');
};
var myObject = {
    foo : 'bar'
};
var myArray = [ 'a', 'b', 'c' ];
var myString = 'ciao;
var myNumber = 3;
typeof myFunction;   // ritorna 'function'
typeof myObject;     // ritorna 'object'
typeof myArray;      // ritorna 'object' -- fare attenzione
typeof myString;     // ritorna 'string';
typeof myNumber;     // ritorna 'number'
typeof null;         // ritorna 'object' -- fare attenzione
if (myArray.push && myArray.slice && myArray.join) {
    // probabilmente è un array
    // (questo stile è chiamato, in inglese, "duck typing")
}
if (Object.prototype.toString.call(myArray) === '[object Array]') {
    // definitivamente è un array;
    // questa è considerata la forma più robusta
    // per determinare se un valore è un array.
}
jQuery fornisce metodi per determinare il tipo di un certo valore. Questi metodi si vedranno più avanti.
La parola chiave this
⤽
In JavaScript, come in molti linguaggi di programmazione object-oriented, this è una parola chiave speciale che fa riferimento all’oggetto in cui il metodo viene invocato. Il valore di this viene determinato utilizzando una serie di semplici passi:

  • Se la funzione viene invocata utilizzando Function.call o Function.apply, this avrà il valore del primo argomento passato al metodo. Se l’argomento è nullo (null) o indefinito (undefined), this farà riferimento all’oggetto globale (l’oggetto window);
  • Se la funzione a invocare viene creata utilizzando Function.bind, this sarà il primo argomento che viene passato alla funzione, al momento della sua creazione;
  • Se la funzione è invocata come metodo di un oggetto, this farà riferimento a detto oggetto;
  • Altrimenti, se la funzione viene invocata come una funzione indipendente, non legata ad alcun oggetto, this farà riferimento all’oggetto globale.
2.41: Una funzione invocata utilizzando Function.call
⤽
Copia codice

var myObject = {
    sayHello : function() {
        console.log('Ciao! il mio nome è ' + this.myName);
    },
    myName : 'Rebecca'
};
var secondObject = {
    myName : 'Colin'
};
myObject.sayHello();
// registra 'Ciao, il mio nome è Rebecca'
myObject.sayHello.call(secondObject);
// registra 'Ciao, il mio nome è Colin'
2.42: Una función creada utilizando Function.bind
⤽
Copia codice

var myName = 'the global object',
    sayHello = function () {
        console.log('Ciao, il mio nome è ' + this.myName);
    },
    myObject = {
        myName : 'Rebecca'
    };
var myObjectHello = sayHello.bind(myObject);
sayHello();       // registra 'Ciao, il mio nome è oggetto globale'
myObjectHello();  // registra 'Ciao, il mio nome è Rebecca'
2.43: Una funzione vincolata ad un oggetto
⤽
Copia codice

var myName = 'oggetto globale',
    sayHello = function() {
        console.log('Ciao, il mio nome è ' + this.myName);
    },
    myObject = {
        myName : 'Rebecca'
    },
    secondObject = {
        myName : 'Colin'
    };
myObject.sayHello = sayHello;
secondObject.sayHello = sayHello;
sayHello();               // registra 'Ciao, il mio nome è oggetto globale'
myObject.sayHello();      // registra 'Ciao, il mio nome è Rebecca'
secondObject.sayHello();  // registra 'Ciao, il mio nome è Colin'
A volte, quando si invoca una funzione che si trova all’interno di uno spazio dei nomi (namespace in inglese) ampio, si può essere tentati di salvare il riferimento alla funzione corrente in una variabile più breve ed accessibile. Tuttavia, è importante non farlo nelle istanze dei metodi, giacché possono portare all’esecuzione del codice errato. Per Esempio:
Copia codice

var myNamespace = {
    myObject : {
        sayHello : function() {
            console.log('Ciao, il mio nome è ' + this.myName);
        },
        myName : 'Rebecca'
    }
};
var hello = myNamespace.myObject.sayHello;
hello();  // registra 'Ciao, il mio nome è undefined'
Per evitare che questi errori si verifichino, è necessario fare riferimento all’oggetto dove il metodo e invocato:
Copia codice

var myNamespace = {
    myObject : {
        sayHello : function() {
            console.log('Ciao!, il mio nome è ' + this.myName);
        },
        myName : 'Rebecca'
    }
};
var obj = myNamespace.myObject;
obj.sayHello();  // registra 'Ciao!, il mio nome è Rebecca'

Ambito
⤽
“L’ambito” (scope in inglese) si riferisce a variabili che sono disponibili in un blocco di codice in un dato tempo. La mancanza di comprensione di questo concetto può essere un’esperienza frustrante durante la depurazione.

Quando una variabile viene dichiarata all’interno di una funzione utilizzando la parola chiave var, è disponibile solo per il codice all’interno della funzione – tutto il codice al di fuori della funzione non può accedere alla variabile. D’altra parte, le funzioni definite all’interno della funzione potranno accedere alla variabile dichiarata.

Le variabili dichiarate all’interno della funzione senza la parola chiave var non rimangono nell’ambito di applicazione della stessa funzione – JavaScript cercherà il luogo dove la variabile è stata precedentemente dichiarata, e nel caso che non sia stata dichiarata, sarà definita nell’ambito globale, il quale può portare a risultati inattesi;
2.44: Le funzioni hanno accesso alle variabili definite all'interno dello stesso ambito

⤽
Copia codice

var foo = 'Ciao';
var sayHello = function() {
    console.log(foo);
};
sayHello();         // mostra nella console 'Ciao'
console.log(foo);   // mostra anche nella console 'Ciao'
2.45: Il codice esterno non può accedere alla variabile definita all'interno della funzione
⤽
Copia codice

var sayHello = function() {
    var foo = 'Ciao';
    console.log(foo);
};
sayHello();         // mostra nella console 'Ciao'
console.log(foo);   // non mostra niente nella console
2.46: Variabili con nomi identici ma diversi valori possono esistere in diversi ambiti
⤽
Copia codice

var foo = 'mondo';
var sayHello = function() {
    var foo = 'ciao';
    console.log(foo);
};
sayHello();         // mostra nella console 'ciao'
console.log(foo);   // mostra nella console 'mondo'
⤽
Copia codice

var myFunction = function() {
    var foo = 'Ciao';
    var myFn = function() {
        console.log(foo);
    };
    foo = 'mondo';
    return myFn;
};
var f = myFunction();
f();  // registra 'mondo' -- errore
2.48: Ambito folle
⤽
Copia codice

// a self-executing anonymous function
(function() {
    var baz = 1;
    var bim = function() { alert(baz); };
    bar = function() { alert(baz); };
})();
console.log(baz);  // La console non mostra nulla,
        // visto che baz è definita nell'ambito
        // della funzione anonima
bar();  // bar è definita al di fuori della funzione
        // anonima dopo essere stata dichiarata senza la
        // parola chiave var; inoltre, come è stata
        // definita all'interno della stessa portata di
        // baz, è possibile interrogare il valore del baz,
        // anche se questa sia definita all'interno
        // della portata della funzione anonima
bim();  // bim non è definito per essere accessibile
        // al di fuori della funzione anonima,
        // quindi viene visualizzato un errore
Chiusure
⤽
Le chiusure (closures in inglese) sono un’estensione del concetto di ambito (scope) – funzioni che hanno accesso alle variabili che sono disponibili all’interno dell’ambito in cui è stata creata la funzione. Se questo concetto è confuso, non preoccuparsi: si capisce meglio attraverso degli esempi.

Nell’sempio 2.47 il modo in cui le funzioni hanno accesso per cambiare il valore delle variabili. Lo stesso comportamento si verifica nelle funzioni create all’interno dei cicli – la funzione “osserva” il cambiamento nella variabile, anche dopo che la funzione sia stata definita, risultando che ad ogni click appaia una finestra di avviso mostrando il valore 5.
2.49: Come impostare il valore di i?

⤽
Copia codice

/* questo non si comporta come desiderato */
/* ogni click visualizzerà una finestra di avviso con il valore 5 */
for (var i=0; i<5; i++) {
    $('<p>click me</p>').appendTo('body').click(function() {
        alert(i);
    });
}
2.50: Impostare il valore di i utilizzando una chiusura
⤽
Copia codice

/* soluzione: "clausurare" il valor di i all'interno di createFunction */
var createFunction = function(i) {
    return function() { alert(i); };
};
for (var i=0; i<5; i++) {
    $('<p>click me</p>').appendTo('body').click(createFunction(i));
}
Le chiusure possono anche essere utilizzate per risolvere i problemi con la parola chiave this, la quale è unica per ogni ambito.
2.51: Utilizzando una chiusura per accedere simultaneamente ad istanze di oggetti interni ed esterni
⤽
Copia codice

var outerObj = {
    myName : 'esterno',
    outerFunction : function () {
        // fornisce un riferimento allo stesso oggetto outerObj
        // da utilizzare all'interno di innerFunction
        var self = this;
        var innerObj = {
            myName : 'interno',
            innerFunction : function () {
                console.log(self.myName, this.myName);
                // registra 'esterno interno'
            }
        };
        innerObj.innerFunction();
        console.log(this.myName);
        // registra 'esterno'
    }
};
outerObj.outerFunction();
Questo meccanismo può essere utile quando si lavora con funzioni di richiamo o retro-chiamate (callbacks in inglese). Tuttavia, in questi casi è preferibile usare Function.bind per evitare qualunque sovraccarico associatoall’ambito (scope).
[nextpage title=”Nozioni di base di jQuery”] $(document).ready()
⤽
Non si può interagire di forma sicura con il contenuto di una pagina fino a quando il documento non è pronto per la manipolazione. jQuery permette rilevare questo stato attaverso la dichiarazione $(document).ready() in modo che il blocco viene eseguito solo una volta che la pagina sia disponibile.
3.1: Il blocco $(document).ready()
⤽
Copia codice

$(document).ready(function() {
    console.log('il ocumento è pronto!');
});
C’è una scorciatoia per $(document).ready() che potete trovare a volte, ma si consiglia di non utilizzare se si scrive codice per le persone che non conoscono jQuery.
3.2: Forma abbreviata per $(document).ready()
⤽
Copia codice

$(function() {
    console.log('il ocumento è pronto!');
});
E’ anche possibile passare a $(document).ready() il nome di una funzione al posto di una anonima.:
3.3: Passare il nome di una funzione al posto di una funzione anonima
⤽
Copia codice

function readyFn() {
    // codice da eseguire quando il documento è pronto
}
$(document).ready(readyFn);
Selezione di elementi
⤽
Il concetto di base di jQuery è quello di “selezionare alcuni elementi ed eseguire azioni su di essi.” La libreria supporta la maggior parte dei selettori CSS3 e molti non standardizzati. In http://api.jquery.com/category/selectors/ può trovare un riferimento completo sui selettori della libreria.

Di seguito sono elencate alcune tecniche comuni per la selezione degli elementi:
3.4: Selezione di elementi in base al loro ID

⤽
Copia codice

$('#myId'); // si noti che l'ID deve essere univoco per ogni pagina
3.5: Selezione di elementi in base al nome della classe
⤽
Copia codice

$('div.myClass'); // se si specifica il tipo di elemento,
                  // si migliora le prestazioni della selezione
3.6: Selezione di elementi per il suo attributo
⤽
Copia codice

$('input[name=first_name]'); // attenzione, che può essere molto lento
3.7: Selezione di elementi in forma di selettore CSS
⤽
Copia codice

$('#contents ul.people li');
3.8: Pseudo-selettori
⤽
Copia codice

$('a.external:first'); // il primo elemento <a> con la classe 'external'
$('tr:odd');           // gli elementi <tr> dispari di una tabella
$('#myForm :input');   // gli elementi del tipo input
$('div:visible');      // gli elementi <div> visibili
$('div:gt(2)');        // gli elementi <div> tranne i primi tre
$('div:animated');     // gli elementi <div> attualmente animati
Quando si utilizzano i pseudo-selettori: :visible e :hidden, jQuery verifica la corrente visibilità del elemento; ma non se questi sono già stati assegnati con gli stili CSS visibility o display – in altre parole, verifica se l’altezza e la larghezza fisica dell’elemento è maggiore di zero. Tuttavia, questo controllo non funziona con gli elementi

; in questo caso, jQuery verifica se si sta’ applicando lo stile display e prenderà in considerazione l’elemento come nascosto se è stato assegnato il valore none. Inoltre, gli elementi che non sono ancora state aggiunte al DOM saranno trattati come nascosti, anche se hanno stili applicati come visibili (nella sezione sulla manipolazione di questo manuale si spiega come creare e aggiungere elementi al DOM)

Per avere un riferimento, il seguente è il frammento di codice che utilizza jQuery per determinare quando un elemento è visibile o meno. I commenti sono stati inseriti per rendere più chiara la sua comprensione:

Copia codice

jQuery.expr.filters.hidden = function( elem ) {
    var width = elem.offsetWidth, height = elem.offsetHeight,
        skip = elem.nodeName.toLowerCase() === "tr";
    // Scelta di Selettori ha 0 di altezza,
    // 0 di larghezza e non è <tr>?
    return width === 0 && height === 0 && !skip ?
        // allora deve essere nascosto (hidden)
        true :
        // ma se ha larghezza e l'altezza e non è un <tr>
        width > 0 && height > 0 && !skip ?
            // allora deve essere visibile
            false :
            // se siamo qui è perché l'elemento ha larghezza
            // e altezza, ma è anche un <tr>, quindi verifica
            // il valore dello stile display applicato attraverso
            // i CSS per decidere se è nascosto o meno
            jQuery.curCSS(elem, "display") === "none";
};
jQuery.expr.filters.visible = function( elem ) {
    return !jQuery.expr.filters.hidden( elem );
};

Scelta di Selettori
⤽
La scelta di buoni selettori è un punto importante quando si desidera migliorare le prestazioni del codice. Un po’ di specificità – per esempio includere il tipo di elemento (ad esempio, div)(come div), quando viene effettuata una selezione dal nome della classe – può aiutare molto. Pertanto, si consiglia di dare alcuni “suggerimenti” a jQuery su dove si può trovare nel documento ciò che si desidera selezionare. D’altra parte, la troppa specificità può essere dannosa. Un selettore come #miaTabella thead tr th.especiale è un eccesso, sarebbe meglio usare #miaTabella th.especiale.

jQuery fornisce molti selettori basati sugli attributi che consentono di fare delle selezioni in base ai contenuti degli attributi utilizzando semplificazioni con delle espressioni regolari.

Copia codice

// trovare tutti gli <a> cui attributi finiscono in "thinger"
$("a[rel$='thinger']");
Questi tipi di selettori possono essere utili ma sono anche molto lenti. Quando possibile, si dovrebbe fare la selezione utilizzando gli ID, i nomi delle classi e nomi dei tag.

Per saperne di più su questo argomento, Paul Irish ha fatto una grande presentazione sui miglioramenti delle prestazioni Javascript (in inglese), diverse diapositive centrate sui selettori.

Verificare Selezioni
⤽
Una volta realizzata la selezione degli elementi, si vorrà sapere se detta selezione ha dato alcuni risultati. Per fare questo, si può scrivere qualcosa del genere:
Copia codice

if ($('div.foo')) { ... }
Tuttavia questo non funzionerà. Quando viene effettuata una selezione con $(), restituisce sempre un oggetto, e se essa viene valutata, ritornerrà sempre true. Anche se la selezione non contiene alcun elemento, il codice all’interno del blocco if viene eseguito.

Invece di utilizzare il codice di prima, la cosa da fare è chiedere il numero di elementi che ha la selezione che è stata eseguita. E’ possibile fare usando la proprietà JavaScript, length. Se la risposta è 0, la condizione restituisce false, altrimenti (più di 0 elementi), la condizione è vera.
3.9: Valutare se una selezione ha degli elementi

⤽
Copia codice

if ($('div.foo').length) { ... }
Salvare Selezioni
⤽
Ogni volta che viene effettuata una selezione, un sacco di codice viene eseguito. jQuery non salva il risultato da se, quindi se si effettua una selezione che poi si farà di nuovo, è necessario salvare la selezione in una variabile.
3.10: Salvare le selezioni su una variabile
⤽
Copia codice

var $divs = $('div');
Nell’esempio “Salvare le selezioni su una variabile”, la variabile inizia con il simbolo del dollaro. A differenza di altri linguaggi di programmazione, in JavaScript, questo segno non ha un significato speciale – è solo un altro carattere. Ma qui è usato per indicare che la variabile è un oggetto jQuery.Questa pratica – una sorta di notazione ungherese – è solo una convenzione e non obbligatoria.

Una volta che la selezione è memorizzata nella variabile, può essere utilizzato in combinazione con i metodi di jQuery e il risultato sarà lo stesso se si utilizza la selezione originale.

La selezione prende solo gli elementi che sono sulla pagina quando tale azione ha avuto luogo. Se poi si aggiungono elementi al documento, sarà necessario ripetere la selezione o aggiungere nuovi elementi alla selezione memorizzata nella variabile. In altre parole, le selezioni salvate non vengono aggiornati “magicamente” quando cambia il DOM.
Affinamento e Filtro delle Selezioni
⤽
A volte si può ottenere una selezione che contiene più del necessario, in questo caso, è necessario affinare la selezione. jQuery fornisce diversi modi per ottenere esattamente quello che si desidera.
3.11: Affinamento delle selezioni
⤽
Copia codice

$('div.foo').has('p');        // l'elemento div.foo contiene elementi <p>
$('h1').not('.bar');          // l'elemento h1 non possiede la clase 'bar'
$('ul li').filter('.current');// un item di una lista non ordinata che
                              // possiede la classe 'current'
$('ul li').first();           // il primo item de una lista non ordinata
$('ul li').eq(5);             // el sesto item de una lista non ordinata
Selezione di elementi di un Form
⤽
jQuery fornisce diverse pseudo-selettori per aiutare a trovare gli elementi nei forms; questi sono particolarmente utili perché a seconda degli stati di ogni elemento o tipo, possono essere difficili distinguergli utilizzando i normali selettori CSS.

  • :button Seleziona elementi <button> e con l’attributo type=”button”
  • :checkbox Seleziona elementi <input> con l’attributotype=”checkbox”
  • :checked Seleziona elementi <input> del tipo checkbox selezionati
  • :disabled Seleziona elementi del form che sono disabilitati
  • :enabled Seleziona elementi del form che sono abilitati
  • :file Seleziona elementi <input> con l’attributo type=”file”
  • :image Seleziona elementi <input> con l’attributo type=”image”
  • :input Seleziona elementi <input>, <textarea> e <select>
  • :password Seleziona elementi <input> con el atributo type=”password”
  • :radio Seleziona elementi <input> con l’attributo type=”radio”
  • :reset Seleziona elementi <input> con l’attributo type=”reset”
  • :selected Seleziona elementi <options> che sono selezionati
  • :submit Seleziona elementi <input> con l’attributo type=”submit”
  • :text Seleziona elementi <input> con l’attributo type=”text”
3.12: Utilizzando pseudo-selettori sugli elementi dei forms
⤽
Copia codice

$('#myForm :input'); // ottiene tutti gli elementi input nel form #myForm
Lavorare con le selezioni
⤽
Una volta realizzata la selezione di elementi, è possibile utilizzareliin in combinazione con diversi metodi. Sono generalmente di due tipi: gli ottenetori (in inglese getters) e gli stabilitori (setters in inglese). I metodi Getter restituiscono una proprietà metodi del elemento selezionato, mentre i metodi Setter fissano una proprietà a tutti gli elementi selezionati.
Concatenazione
⤽
Se in una selezione viene effettuata una chiamata a un metodo e restituisce un oggetto jQuery, è possibile seguire un metodo “incatenato” nell’oggetto.
3.13: Concatenando
⤽
Copia codice

$('#content').find('h3').eq(2).html('testo per il terzo elemento h3!');
D’altra parte, se si sta scrivendo una serie di metodi che includono molti passi, e possibile scriverli linea per linea, rendendo l’aspetto del codice più piacevole da leggere.
3.14: Formattazione del codice incatenato
⤽
Copia codice

$('#content')
    .find('h3')
    .eq(2)
    .html('testo per il terzo elemento h3!');
Per tornare alla selezione originale in mezzo alla concatenazione, jQuery fornisce il metodo $.fn.end per farlo.
3.15: Ripristinare la selezione originale utilizzando il metodo $.fn.end
⤽
Copia codice

$('#content')
    .find('h3')
    .eq(2)
    .html('testo per il terzo elemento h3!')
    .end() // ripristina tutti gli elementi h3 in #content
    .eq(0)
    .html('testo per il primo elemento h3!');
La concatenazione è molto potente ed è una caratteristica che molte librerria JavaScript hanno adottato da che jQuery è diventato popolare. Tuttavia, dovrebbe essere usato con cautela. Una concatenazione di metodi estensivi può rendere il codice molto difficile da modificare e depurare. Non c’è una regola che indichi quanto lungo o corto dovrebbe essere la concatenazione – ma si dovrebbe prendere in considerazione questo consiglio.
Ottenitori (Getters) & Impostatori (Setters)
⤽
jQuery “sovraccarica” i suoi metodi, in altre parole, il metodo per impostare un valore ha lo stesso nome del metodo per ottenere un valore. Quando un metodo viene utilizzato per impostare un valore, il metodo viene chiamato impostatori (setter inglese). Tuttavia, quando un metodo viene utilizzato per ottenere (o leggere) un valore si chiama ottenitori (getter in inglese).
3.16: Il metodo $.fn.html utilizzato come impostatore
⤽
Copia codice

$('h1').html('ciao mondo');
3.17: Il metodo html utilizzato come ottenitore
⤽
Copia codice

$('h1').html();
I metodi impostatori restituiscono un oggetto jQuery, che consente di continuare la chiamata sui più metodi nella stessa selezione, mentre i metodi ottenitori restituisce il valore che è stato consultato, ma non possono continuare ad invocare altri metodi su quel valore.
CSS, Stili & Dimensioni
⤽
jQuery include un modo utile per ottenere e impostare le proprietà CSS agli elementi.

Le proprietà CSS che includono un trattino in mezzo come separatore, in JavaScript deve essere trasformato nel suo stile CamelCase. Per Esempio quando la proprietà è usata come un metodo, lo stile CSS font-size dovrà essere espressa come fontSize. Tuttavia, questa regola non viene applicata quando si passa il nome della proprietà CSS al metodo $.fn.css. – In questo caso, i due formati (in CamelCase o con il trattino in mezzo) funzionano.
3.18: Ottenendo le proprietà CSS
⤽
Copia codice

$('h1').css('fontSize');  // restituisce una stringa come "19px"
$('h1').css('font-size'); // funziona lo stesso
3.19: Impostando le proprietà CSS
⤽
Copia codice

// imposta una proprietà singola CSS
$('h1').css('fontSize', '100px');
// imposta molteplici proprietà CSS
$('h1').css({ 'fontSize' : '100px', 'color' : 'red' });
Si noti che lo stile dell’argomento utilizzato nella quarta linea dell’esempio – è un oggetto che contiene più proprietà. Questo è un modo comune per passare argomenti a una funzione, e molti metodi impostatori della libreria accettano oggetti per fissare varie proprietà in una sola volta.
Utilizzare Classi per applicare Stili CSS
⤽
Per ottenere i valori degli stili applicati a un elemento, il metodo $. $.fn.css è molto utile, tuttavia il suo uso come metodo impostatore (setter) deve essere evitato (giacché, per applicare degli stili a un elemento, si può fare direttamente da CSS ). Al suo posto, l’ideale sarebbe quello di scrivere le regole CSS da applicare alle classi che descriverebbero i vari stati visuali degli elementi e quindi modificare la classe degli elementi per applicare lo stile che si desidera visualizzare.
3.20: Lavorare con le classi
⤽
Copia codice

var $h1 = $('h1');
$h1.addClass('big');
$h1.removeClass('big');
$h1.toggleClass('big');
if ($h1.hasClass('big')) { ... }
Le classi possono anche essere utile per salvare qualche informazione di stato, per esempio, per indicare che un elemento è stato selezionato.
Dimensioni
⤽
jQuery offre una varietà di metodi per ottenere e impostare valori di dimensioni e posizione di un elemento.

Il codice riportato nell’esempio “Dimensioni – Metodi di base” è solo un breve riassunto delle funzionalità sui rapporti dimensionali di jQuery, tutti i dettagli possono essere trovati http://api.jquery.com/category/dimensions/.
3.21: Dimensioni - Metodi di base

⤽
Copia codice

$('h1').width('50px'); // imposta la larghezza di tutti gli elementi H1
$('h1').width();       // ottiene la larghezza del primo elemento H1
$('h1').height('50px');// imposta l'altezza di tutti gli elementi H1
$('h1').height();      // Ottiene l'altezza del primo elemento H1
$('h1').position();    // Restituisce un oggetto che contiene informazioni
                       // circa la posizione del primo elemento relativo a
                       // "offset" (posizione) dal suo elemento genitore
Attributi
⤽
Gli attributi degli elementi HTML che costituiscono un’applicazione può contenere informazioni utili, quindi è importante potere impostare e ottenere queste informazioni.

Il metodo $.fn.attr funge sia da metodo getter che da metodo setter. Inoltre, come metodo di $.fn.css, se usato come metodo setter può accettare una serie di parole chiave-valore o un oggetto che contiene più serie.
3.22: Impostare attributi

⤽
Copia codice

$('a').attr('href', 'allMyHrefsAreTheSameNow.html');
$('a').attr({
    'title' : 'con i titoli è la stessa cosa!',
    'href' : 'somethingNew.html'
});
Nell’esempio, l’oggetto passato come argomento è scritto in diverse linee. Come spiegato in precedenza, gli spazi non contano in JavaScript, quindi si è liberi di usarli per rendere il codice più leggibile. In ambienti di produzione, è possibile utilizzare strumenti di minimizzazione, che elimina gli spazi in bianco (tra le altre cose) e comprimere il file di output.
3.23: Ottenere attributi
⤽
Copia codice

$('a').attr('href');  // restituisce il primo valore dell'attributo href
                      // appartenente al elemento <a> del documento
Attraversare il DOM
⤽
Una volta ottenuta la selezione, è possibile trovare altri oggetti utilizzando la stessa selezione.

In http://api.jquery.com/category/traversing/ può trovare una documentazione completa sui metodi di attraversamento del DOM (in inglese traversing) che ha jQuery.

Si deve fare attenzione nel percorrere lunghe distanze in un documento — percorsi complessi richiedono che la struttura del documento sia sempre la stessa, cosa che è difficile da garantire. Uno – o due – step per il giro va bene, ma generalmente bisogna evitare di attraversare da un contenitore all’altro.
3.24: Muoversi attraverso il DOM usando metodi di attraversamento
⤽
Copia codice

$('h1').next('p');           // seleziona l'elemento successivo <p>
                             // immediatamente dopo <h1>
$('div:visible').parent();   // seleziona il contenitore padre
                             // di un elemento <div> visibile
$('input[name=first_name]').closest('form');  // seleziona dal più
                                              // vicino <form> un input
$('#myList').children();     // seleziona tutti gli elementi figlio
                             // di #myList
$('li.selected').siblings(); // seleziona tutti gli elementi fratelli
                             // del elemento <li>
È possibile interagire con la selezione utilizzando il metodo $.fn.each. Questo metodo interagisce con tutti gli elementi ottenuti nella selezione ed esegue una funzione per ciascuno. La funzione prende come argomento l’indice dell’elemento corrente e lo stesso elemento. Per impostazione predefinita, all’interno della funzione, è possibile fare riferimento all’elemento DOM attraverso la dichiarazione this.
3.25: Interagire in una selezione
⤽
Copia codice

$('#myList li').each(function(idx, el) {
    console.log(
        'L\'elemento ' + idx +
        'ha il seguente html: ' +
        $(el).html()
    );
});
Manipolazione di Elementi
⤽
Una volta realizzata la selezione degli elementi che si desidera utilizzare, “inizia il divertimento”. È possibile modificare, spostare, rimuovere e duplicare. Anche crearne di nuovi attraverso una sintassi semplice.

La documentazione completa sui metodi di manipolazione può essere trovata in http://api.jquery.com/category/manipulation/.
Ottenre e Impostare Informazioni negli Elementi

⤽
Ci sono molti modi in cui è possibile modificare un elemento. Tra le operazioni più comuni ci sono quelle per cambiare l’HTML all’interno o qualche suo attributo. Per questi compiti, jQuery fornisce metodi semplici e funzionali in tutti i browser moderni. E’ anche possibile ottenere informazioni sugli elementi utilizzando gli stessi metodi, ma nel loro metodo come ottenitore getter.

Apportare modifiche agli elementi, è un lavoro banale, ma ricordate che la modifica interesserà tutti gli elementi nella selezione, quindi se si vuole cambiare un singolo elemento, è necessario assicurarsi di specificarlo nella selezione prima di chiamare il metodo impostatore setter.
Quando i metodi agiscono come ottenitori getter, solitamente lavorano solo con il primo elemento della selezione. Inoltre non restituiscono nessun oggetto jQuery, quindi non è possibile concatenare più metodi su di esso. Un’eccezione è il metodo $.fn.text, che consente di ottenere il testo degli elementi della selezione.
  • $.fn.html Ottiene o imposta il contenuto HTML di un elemento.
  • $.fn.text Ottiene o imposta il contenuto in texto piano dell’elemento; nel caso di pasarli come argomento del codice HTML, questo sarà ripulito dai sui tag.
  • $.fn.attr Ottiene o imposta il valore di un determinato attributo.
  • $.fn.width Ottiene o imposta la larghezza in pixels del primo elemento della selezione come un intero.
  • $.fn.height Ottiene o imposta l’altezza in pixeles del primo elemento della selezione come un intero.
  • $.fn.position Ottiene un oggetto con informazioni sulla posizione del primo elemento della selezione relativa al primo elemento genitore posizionato. Questo metodo è solo ottenitore (getter).
  • $.fn.val Ottiene o imposta il valore (value) negli elementi dei forms.
3.26: Modificare il codice HTML di un elemento
⤽
Copia codice

$('#myDiv p:first')
    .html('Nuovo <strong>primo</strong> parragrafo!');
Spostare, copiare e rimuovere Element
⤽
Ci sono diversi modi per spostare gli elementi attraverso del DOM, i quali si possono suddividere in due approcci:

  • Volere mettere il/gli elementi selezionati rispetto ad altri elementi
  • Volere mettere un elemento rispetto ad altri elementi selezionati.

Per esempio, jQuery fornisce metodi $.fn.insertAfter e $.fn.after. Il metodo $.fn.insertAfter colloca il/gli elementi selezionati dopo l’elemento che è stato passato come argomento, mentre il metodo $.fn.after colloca l’elemento passato come argomento dopo l’elemento selezionato. Altri metodi seguono anche questo modello:

  • $.fn.insertBefore e $.fn.before;
  • $.fn.appendTo e $.fn.append;
  • e $.fn.prependTo e $.fn.prepend.

L’uso di uno o un altro metodo dipende dagli elementi che hanno selezionato e il tipo di riferimento che si desidera salvare rispetto all’elemento che si sta muovendo.
3.27: Spostare oggetti con differenti approcci

⤽
Copia codice

// fare il che primo elemento della lista sia l'ultimo
var $li = $('#myList li:first').appendTo('#myList');
// un altro approccio allo stesso problema
$('#myList').append($('#myList li:first'));
// Va notato che non c'è modo di accedere
// alla lista degli items che è stata spostata,
// giacché restituisce la lista stessa
Clonare Elementi
⤽
Quando si utilizza un metodo come $.fn.appendTo, ciò che si sta facendo è spostare all’elemento, ma a volte, anziché questo, si vuole spostare un duplicato dell’elemento. In questo caso, è possibile utilizzare il metodo $.fn.clone.
3.28: Ottenere una copia del elemento
⤽
Copia codice

// copiare il primo elemento della lista
// e spostarlo alla fine dello stesso
$('#myList li:first').clone().appendTo('#myList');
Se avete bisogno di copiare le informazioni e gli eventi legati al elemento, si deve passare true come argomento di $.fn.clone.
Rimuovere Elementi
⤽
Ci sono due modi per rimuovere gli elementi di una pagina: Utilizzando $.fn.remove ó $.fn.detach. Quando si desidera rimuovere l’elemento in modo permanente, utilizzare il metodo $.fn.remove.

D’altra parte, il $.Fn.detach rimuove anche l’elemento, ma conserva le informazioni e gli eventi associati ad esso, essendo utile in caso di necessità di reinserire l’elemento nel documento.

Il metodo $.fn.detach è molto utile quando si manipola fortemente un elemento, giacché è possibile eliminare l’elemento, lavorarlo nel codice e quindi ripristinarlo nuovamente sulla pagina. Questa forma ha il vantaggio di non toccare il DOM mentre si sta modificando delle informazioni e gli eventi dell’elemento.

D’altra parte, se si desidera mantenere l’elemento, ma si ha bisogno di rimuovere i uso contenuto, è possibile utilizzare il metodo $.fn.empty, il quale “svuoterà” il contenuto HTML dell’elemento.

Creare nuovi Elementi
⤽
jQuery fornisce un modo semplice ed elegante per creare nuovi oggetti utilizzando lo stesso metodo di $() che viene utilizzato per effettuare selezioni.
3.29: Creare nuovi elementi
⤽
Copia codice

$('<p>Questo è un nuovo paragrafo</p>');
$('<li class="nuovo">nuovo item della lista</li>');
3.30: Creare un nuovo elemento con attributi utilizzando un oggetto
⤽
Copia codice

$('<a/>', {
    html : 'Questo è un <strong>nuovo</strong> link',
    'class' : 'nuovo',
    href : 'foo.html'
});
Si noti che nell’oggetto che si passa come argomento, la proprietà class è tra virgolette, mentre la proprietà href e html non lo sono. In generale, i nomi delle proprietà non dovrebbero essere tra virgolette, ad eccezione dei nomi che vengono usati come una parola riservata (come nel caso della classe).

Quando si crea un elemento, non è immediatamente aggiunto alla pagina, ma se deve farlo in combinazione con un metodo.
3.31: Creare un nuovo elemento nella pagina

⤽
Copia codice

var $myNewElement = $('<p>Nuovo elemento</p>');
$myNewElement.appendTo('#content');
$myNewElement.insertAfter('ul:last');
// eleminerà l'elemento <p> esistente in #content!
$('ul').last().after($myNewElement.clone());
// clonare l'elemento <p> per avere due versioni
A rigor di termini, non è necessario salvare l’elemento creato in una variabile – è possibile chiamare il metodo per aggiungere l’elemento direttamente subito dopo il $().

Tuttavia, la maggior parte delle volte si desidererà fare riferimento all’elemento aggiunto, e quindi, se si salva in una variabile non c’è bisogno di selezionarlo più tardi.
3.32: Creare e aggiungere allo stesso tempo un elemento alla pagina

⤽
Copia codice

$('ul').append('<li>item della lista</li>');
La sintassi per aggiungere nuovi elementi alla pagina è molto facile da usare, ma si è tentati di dimenticare che esiste un enorme costo in termini di prestazioni mentre si aggiunge degli elementi al DOM ripetutamente. Se si sta aggiungendo molti elementi allo stesso contenitore, piuttosto che aggiungere ogni elemento uno per volta, il migliore sistema è quella di concatenare tutto l’HTML in una singola catena di stringhe e poi allegarla al contenitore. Una possibile soluzione è quella di utilizzare un array che contenga tutti gli elementi e poi unirli usando join per finalmente allegarla.
Copia codice

var myItems = [], $myList = $('#myList');
for (var i=0; i<100; i++) {
    myItems.push('<li>item ' + i + '</li>');
}
$myList.append(myItems.join(''));

Manipolazione di Attributi
⤽
Le capacità per la gestione degli attributi che offre la libreria jQuery sono ampie. L’esecuzione di modifiche di base sono semplici, ma il metodo $.fn.attr consente manipolazioni complesse.
3.33: Manipolazione di un singolo attributo
⤽
Copia codice

$('#myDiv a:first').attr('href', 'newDestination.html');
3.34: Manipolazione di più attributi
⤽
Copia codice

$('#myDiv a:first').attr({
    href : 'newDestination.html',
    rel : 'super-special'
});
3.35: Utilizzare una funzione per determinare il valore del nuovo attributo
⤽
Copia codice

$('#myDiv a:first').attr({
    rel : 'super-special',
    href : function(idx, href) {
        return '/new/' + href;
    }
});
$('#myDiv a:first').attr('href', function(idx, href) {
    return '/new/' + href;
});
Esercizi
⤽
Selezioni
⤽
Aprire il file /exercises/index.html nel tuo browser. Eseguire l’esercizio utilizzando il file /exercises/js/sandbox.js o lavorare direttamente con Firebug per compiere i seguenti punti:

  • Selezionare tutti gli elementi div che hanno classe “module”.
  • Specificare tre selezioni che possono selezionare il terzo item della lista non ordinata #myList. Qual è il migliore da usare e perché?
  • Selezionare l’elemento label dell’elemento input mediante un selettore di attributo.
  • Verificare quanti elementi della pagina sono nascosti (suggerimento:. .length)
  • Verificare quante immagini sulla pagina hanno l’attributo alt.
  • Selezionare tutte le righe dispari del corpo della tabella.
Percorrere il DOM
⤽
Aprire il file /exercises/index.html nel tuo browser. Eseguire l’esercizio utilizzando il file /exercises/js/sandbox.js o lavorare direttamente con Firebug per compiere i seguenti punti:

  • Selezionare tutte le immagini sulla pagina, registrare nella console l’attributo alt di ogni immagine.
  • Selezionare l’elemento di input, poi andare al form e aggiungere una classe ad esso.
  • Selezionare l’item che ha la classe di “current” nella lista #myList e rimuovere la classe, poi aggiungere la classe “current” al successivo item della lista.
  • Selezionare l’elemento select all’interno di #special; per poi dirigersi verso il pulsante submit.
  • Selezionare il primo item della lista nell’elenemto #slideshow; aggiungere la classe “current” ad esso e poi aggiungere la classe “disabled” agli elementi fratelli.
Manipolazione
⤽
Aprire il file /exercises/index.html nel tuo browser. Eseguire l’esercizio utilizzando il file /exercises/js/sandbox.js o lavorare direttamente con Firebug per compiere i seguenti punti:

  • Aggiungere 5 nuovi elementi alla fine della lista non ordinata # myList. Suggerimento:
    Copia codice
    
    for (var i = 0; i<5; i++) { ... }
    
  • Rimuovere gli elementi dispari dalla lista.
  • Aggiungere un altro elemento h2 e un altro paragrafo all’ultimo div.module.
  • Aggiungere un’altra opzione all’elemento select, danno all’opzione aggiunta il valore “Wednesday”.
  • Aggiungere un nuovo div.module alla pagina dopo l’ultima pagina; e quindi aggiungere una copia di una delle immagini esistenti nel nuovo div.
[nextpage title=”Il nucleo di jQuery”] $ vs $()
⤽
Finora, è stato trattato pienamente con i metodi che vengono chiamati dall’oggetto jQuery. Per Esempio:
Copia codice

$('h1').remove();
Tali metodi fanno parte dello spazio dei nomi (namespace in inglese) $.fn, o prototipo (prototype in inglese) jQuery, e sono considerati come metodi dell’oggetto jQuery.

Tuttavia, ci sono metodi che fanno parte del namespace $ e sono considerati come metodi del nucleo di jQuery.

Queste distinzioni possono essere molto confuse per i nuovi utenti. Per evitare confusione, ricordare questi due punti:

  • I metodi utilizzati nelle selezioni si trovano all’interno dello spazio dei nomi $.fn, e automaticamente ricevono e restituiscono una selezione in sè.
  • Metodi nello spazio dei nomi $ sono generalmente metodi per diverse utilità, non lavorano con le selezioni, non vengono passati argomenti e valore di ritorno può variare.

Ci sono alcuni casi in cui i metodi dell’oggetto e del nucleo hanno gli stessi nomi, come succede con $.each e $.fn.each. In questi casi, è necessario fare attenzione a leggere attentamente la documentazione per sapere quale oggetto usare in modo corretto.

Metodi di utilità
⤽
jQuery fornisce diversi metodi di utilità all’interno dello spazio dei nomi $. Questi metodi sono di grande aiuto per svolgere compiti di routine di programmazione.
Di seguito alcuni esempi, per una documentazione completa visita http://api.jquery.com/category/utilities/.
$.trim
⤽
Rimuove gli spazi bianchi all’inizio e alla fine.
Copia codice

$.trim('    stringa con più spazi vuoti    ');
// restituisce 'stringa con più spazi vuoti'
$.each
⤽
Interagisce negli array e negli oggetti.
Copia codice

$.each([ 'foo', 'bar', 'baz' ], function(idx, val) {
    console.log('elemento ' + idx + 'es ' + val);
});
$.each({ foo : 'bar', baz : 'bim' }, function(k, v) {
    console.log(k + ' : ' + v);
});
Come accennato in precedenza, c’è un metodo chiamato $.fn.each, che interagisce in una selezione di elementi.

$.inArray
⤽
Restituisce l’indice di un valore in una matrice, o -1 se il valore non si trova nella matrice.
Copia codice

var myArray = [ 1, 2, 3, 5 ];
if ($.inArray(4, myArray) !== -1) {
    console.log('valore trovato!');
}
$.extend
⤽
Cambia le proprietà del primo oggetto utilizzando le proprietà degli oggetti successivi.
Copia codice

var firstObject = { foo : 'bar', a : 'b' };
var secondObject = { foo : 'baz' };
var newObject = $.extend(firstObject, secondObject);
console.log(firstObject.foo); // 'baz'
console.log(newObject.foo);   // 'baz'
Se non si desidera modificare le proprietà di nessun oggetto che vengono utilizzati in $.extend, si deve includere un oggetto vuoto come primo argomento.
Copia codice

var firstObject = { foo : 'bar', a : 'b' };
var secondObject = { foo : 'baz' };
var newObject = $.extend({}, firstObject, secondObject);
console.log(firstObject.foo); // 'bar'
console.log(newObject.foo);   // 'baz'
$.proxy
⤽
Restituisce una funzione che si eseguirà sempre nel campo di applicazione (scope) fornito – in altre parole, stabilisce il significato di this (incluso all’interno della funzione) come secondo argomento.
Copia codice

var myFunction = function() { console.log(this); };
var myObject = { foo : 'bar' };
myFunction(); // restituisce l'oggetto window
var myProxyFunction = $.proxy(myFunction, myObject);
myProxyFunction(); // restituisce l'oggetto myObject
Se si dispone di un oggetto con metodi, è possibile passare l’oggetto e il nome di un metodo per restituire una funzione che si eseguirà sempre nell’ambito di tale oggetto.
Copia codice

var myObject = {
    myFn : function() {
        console.log(this);
    }
};
$('#foo').click(myObject.myFn);
// registra el elemento DOM #foo
$('#foo').click($.proxy(myObject, 'myFn'));
// registra myObject
Verificazione dei Tipi
⤽
Come accennato nel capitolo “Concetti di base di JavaScript” jQuery fornisce diversi metodi utili per determinare il tipo di un valore specifico.
4.1: Verificare il tipo di un determinato valore
⤽
Copia codice

var myValue = [1, 2, 3];
// Utilizzare l'operatore typeof di JavaScript
// per controllare tipi primitivi
typeof myValue == 'string';    // false (falso)
typeof myValue == 'number';    // false (falso)
typeof myValue == 'undefined'; // false (falso)
typeof myValue == 'boolean';   // false (falso)
// Utilizzare l'operatore di uguaglianza rigorosa
// per controllare i valori nulli
myValue === null; // false  (falso)
// Utilizzare metodi di jQuery per testare
// i tipi non primitivi
jQuery.isFunction(myValue);    // false (falso)
jQuery.isPlainObject(myValue); // false (falso)
jQuery.isArray(myValue);       // true (vero)
Il Metodo Data
⤽
Spesso vi accorgerete che ci sono informazioni su un elemento che ha bisogno di essere salvate. In JavaScript è possibile farlo con l’aggiunta di proprietà all’elemento DOM, ma questa pratica implica avere a che fare con perdite di memoria (memory leaks in inglese) in alcuni browser. jQuery fornisce un modo semplice per memorizzare informazioni relative a un elemento, e la stessa libreria è responsabile per affrontare i problemi che possono nascere dalla mancanza di memoria.
4.2: Salvare e recuperare informazioni relative a un elemento
⤽
Copia codice

$('#myDiv').data('keyName', { foo : 'bar' });
$('#myDiv').data('keyName'); // { foo : 'bar' }
Attraverso il metodo $.fn.data si possono salvare qualunque tipo di informazioni su un elemento, ed è difficile esagerare l’importanza di questo concetto durante lo sviluppo di un’applicazione complessa.

Per esempio, se si vuole stabilire una relazione tra l’item di una lista e il div che è all’interno di questo item, è possibile farlo ogni volta che si interagisce con l’item, ma una soluzione migliore è farlo una sola volta, salvando un puntatore al div utilizzando il metodo $.fn.data:
4.3: Relazione tra gli elementi utilizzando il metodo $.fn.data

⤽
Copia codice

$('#myList li').each(function() {
    var $li = $(this), $div = $li.find('div.content');
    $li.data('contentDiv', $div);
});
// poi, non si deve tornare a cercare al div;
// è possibile leggerlo dall'informazione
// associata all'item della lista
var $firstLi = $('#myList li:first');
$firstLi.data('contentDiv').html('nuovo contenuto');
E’ anche possibile passare al metodo u$.fn.data n oggetto contenente una o più coppie di parole chiave-valore.
Rilevamento browser e caratteristiche
⤽
Con jQuery, oltre a rimuovere la maggior parte delle caratteristiche di JavaScript tra ogni browser, ci sono dei momenti in cui è necessario eseguire codice su un browser specifico.

Per tali situazioni, jQuery fornisce l’oggetto $.support e $.browser (quest’ultimo non più utilizzato). Una documentazione completa su questi oggetti si trovano in http://api.jquery.com/jQuery.support/ e http://api.jquery.com/jQuery.browser/

L’obiettivo di $.support è quello di determinare quali caratteristiche supporta il browser.

L’oggetto $.browser rileva il tipo di browser e la sua versione. Questo oggetto è deprecato (anche se nel breve termine non è previsto l’eliminazione dal nucleo della libreria) e si raccomanda utilizzare l’oggetto $.support per questi scopi.

Evitare conflitti con altre librerie JavaScript
⤽
Se si sta utilizzando jQuery in combinazione con altre librerie JavaScript, i quali utilizzano anche la variabile $, può generare un certo numero di errori. Per risolvere il problema, è necessario mettere a jQuery in modo “non-conflitto”. Questo dovrebbe essere fatto immediatamente dopo che jQuery si carichi sulla pagina e prima che il codice venga eseguito.

Quando jQuery è impostato in modo “non-conflitto”, la libreria offre la possibilità di assegnare un nome per sostituire la variabile $.
4.4: Mettere jQuery in modo non-conflitto

⤽
Copia codice

// la libreria prototype utilizza anche $
<script src="prototype.js"></script>
// si carica jquery nella pagina
<script src="jquery.js"></script>
// se inizializza $j in modo "non-conflitto"
<script>var $j = jQuery.noConflict();</script>
E ‘anche possibile continuare a utilizzare $ contenente il codice in una funzione anonima auto-eseguibile. Questo è un modello standard per la creazione di estensioni alla libreria, dal momento che $ rimane racchiusa all’interno del campo di applicazione della stessa funzione anonima.
4.5: Utilizzare $ all'interno di una funzione anonima auto-eseguibile
⤽
Copia codice

<script src="prototype.js"></script>
<script src="jquery.js"></script>
<script>
jQuery.noConflict();
(function($) {
   // codice va qui, e può utilizzare $
})(jQuery);
</script>
[nextpage title=”Eventi”] Introduzione
⤽
jQuery fornisce i metodi per associare i gestori di eventi (event handlers in inglese) ai selettori. Quando si verifica un evento, la funzione fornita viene eseguita. All’interno della funzione, la parola chiave $this fa riferimento all’elemento in cui si verifica l’evento.
Per maggiori dettagli sugli eventi in jQuery, è possibile consultare http://api.jquery.com/category/events/.
La funzione del gestore di eventi è in grado di ricevere un oggetto. Questo oggetto può essere utilizzato per determinare la natura del evento o, per esempio, evitare il suo comportamento predefinito.
Per maggiori informazioni sull’oggetto dell’evento, visitare http://api.jquery.com/category/events/event-object/.
Vincolare Eventi a Elementi
⤽
jQuery fornisce metodi per la maggior parte degli eventi — tra questi ci sono $.fn.click, $.fn.focus, $.fn.blur, $.fn.change, etc. Queste ultime sono le versioni ridotte del metodo $.fn.bind di jQuery. Il metodo bind è utile per vincolare (in inglese binding) la stessa funzione di gestore degli eventi a più eventi, per quando si desidera fornire le informazioni al gestore di eventi, quando si lavorando con eventi personalizzati o quando si desidera passare un oggetto a più eventi e controllori.

5.1: Collegamento di un evento utilizzando un metodo ridotto
⤽
Copia codice

$('p').click(function() {
    console.log('click');
});
5.2: Collegamento di un evento utilizzando il metodo $.fn.bind
⤽
Copia codice

$('p').bind('click', function() {
    console.log('click');
});
5.3: Collegamento di un evento utilizzando il metodo $.fn.bind con informazione associata
⤽
Copia codice

$('input').bind(
    'click change',  // è possibile collegare più eventi
                     // all'elemento
    { foo : 'bar' }, // deve essere passato come argomento
                     // le informazioni associatea
    function(eventObject) {
        console.log(eventObject.type, eventObject.data);
        // registra il tipo di evento e l'informazione
        // associata { foo : 'bar' }
    }
);
Collegare Eventi per essere eseguiti una sola volta
⤽
A volte potrebbe essere necessario che un controller particolare venga eseguito solo una volta – e dopo di questo, abbiamo bisogno che nessun altro si esegua, o fare eseguire uno diverso. A tal fine, jQuery fornisce il metodo $.fn.one.

5.4: Cambiare controller usando il metodo $.fn.one method
⤽
Copia codice

$('p').one('click', function() {
    console.log('fatto click la prima volta!');
    $(this).click(function() { console.log('fatto click di nuovo!'); });
});
Il metodo $.fn.one è utile per situazioni in cui è necessario eseguire un certo codice la prima volta che si verifica un evento su un elemento, ma non in eventi successivi.
Scollegare Eventi
⤽
Per scollegare (in inglese unbind) un gestore di eventi, è possibile utilizzare il metodo $.fn.unbind passando il tipo di evento da scollegare. Se si passa come allegato di una funzione chiamata, è possibile isolare lo scollegamento di tale funzione come secondo argomento.

5.5: Scollegare tutti i controllori di evento click in una selezione
⤽
Copia codice

$('p').unbind('click');
5.6: Scollegare un controllore di evento particolare click
⤽
Copia codice

var foo = function() { console.log('foo'); };
var bar = function() { console.log('bar'); };
$('p').bind('click', foo).bind('click', bar);
$('p').unbind('click', bar); // foo è lagato all'evento click
Spazio di Nomi per gli Eventi
⤽
Nello sviluppo di applicazioni complesse o estensioni di jQuery, può essere utile usare i spazi di nomi (in inglese namespace) per gli eventi, e quindi prevenire che si scolleghino eventi quando no lo si desidera.
5.7: Spazio di Nomi per gli Eventi
⤽
Copia codice

$('p').bind('click.myNamespace', function() { /* ... */ });
$('p').unbind('click.myNamespace');
$('p').unbind('.myNamespace');
// scollega tutti gli eventi con
// lo spazio dei nomi myNamespace
Collegamento di più eventi
⤽
Molto spesso, gli elementi in un’applicazione sono collegati ad eventi multipli, ognuno con una funzione diversa. In questi casi è possibile passare un oggetto in $.fn.bind con una o più coppie di nomi chiave/valore. Ogni nome chiave sarà il nome dell’evento, mentre ogni valore sarà la funzione da eseguire quando si verifica l’evento.
5.8: Collegare più eventi a un elemento
⤽
Copia codice

$('p').bind({
	'click': function() {
		console.log('fatto click!');
	},
	'mouseover': function() {
		console.log('il mouse è sopra!');
	}
});
L’opzione di passare un oggetto con più eventi e funzioni a $.fn.bind è stato introdotto in jQuery 1.4.4.
L'Oggetto del Evento
⤽
Come accennato nell’introduzione, la funzione di gestore di eventi riceve un oggetto del evento, il quale contiene diversi metodi e proprietà. L’oggetto viene comunemente utilizzato per prevenire l’azione predefinita del evento attraverso il metodo preventDefault. Tuttavia, contiene anche diverse proprietà e metodi utili:

  • pageX, pageY La posizione del mouse quando l’evento si è verificato, relativa la parte superiore e sinistra della pagina.
  • type Il tipo di evento (per esempio “click”).
  • which Il pulsante o tasto premuto.
  • data Informazioni passate quando l’evento viene eseguito.
  • target L’elemento DOM che ha inizializzato l’evento.
  • preventDefault() Annulla l’azione predefinita dell’evento (per esempio: seguire un link).
  • stopPropagation() Ferma la diffusione dell’evento su altri elementi.

D’altra parte, il funzione controller ha anche accesso all’elemento DOM che ha inizializzato l’evento attraverso la parola chiave this. Per convertire l’elemento DOM in un oggetto jQuery (e potere utilizzare i metodi della libreria) deve essere scritto $(this), come illustrato di seguito:

Copia codice

var $this = $(this);
5.9: Annullare che facendo click su un link, questo si esegua
⤽
Copia codice

$('a').click(function(e) {
    var $this = $(this);
    if ($this.attr('href').match('evil')) {
        e.preventDefault();
        $this.addClass('evil');
    }
});
Esecuzione automatica dei Controllori di Eventi
⤽
Attraverso il metodo $.fn.trigger, JQuery fornisce un modo per attivare i gestori di eventi su un elemento senza richiedere intervento dell’utente. Anche se questo metodo ha i suoi usi, non dovrebbe essere utilizzato per chiamare semplicemente una funzione che può essere eseguito con un clic dell’utente. Invece, si dovrebbe salvare la funzione che è necessario chiamare in una variabile e quindi passare il nome della variabile quando si effettua il collegamento (binding). In questo modo, è possibile chiamare la funzione ogni volta che si vuole invece di eseguire $.fn.trigger.
5.10: Sparare un gestore di eventi nel modo giusto
⤽
Copia codice

var foo = function(e) {
    if (e) {
        console.log(e);
    } else {
        console.log('questa azione non proviene da un evento!');
    }
};
$('p').click(foo);
foo(); // invece di eseguire $('p').trigger('click')
Incrementare le prestazioni con la delegazione di Eventi
⤽
Quando si lavora con jQuery, spesso si aggiungono nuovi elementi alla pagina, e quando lo si fa, è necessario collegare eventi a di questi elementi — eventi che erano già collegati agli elementi nella pagina. Piuttosto che ripetere l’operazione ogni volta che si aggiunge un elemento, si può usare la delega di eventi. Con questo, è possibile associare un evento a un elemento contenitore, e poi, quando si verifica l’evento, è possibile vedere in quale elemento succede. Se tutto questo suona complicato, fortunatamente jQuery lo rende facile attraverso i metodi $.fn.live e $.fn.delegate.

La delega di eventi ha alcuni benefici, anche se non avete in programma di aggiungere altri elementi alla pagina. Il tempo necessario per legare i gestori di eventi a centinaia di elementi non è un lavoro banale; se si dispone di un grande insieme di elementi, è consigliabile utilizzare la delegazione di eventi a un elemento contenitore.

Il metodo $.fn.live è stato introdotto dalla versione 1.3 della libreria e poi, solo determinati tipi di eventi erano supportati. A partire dalla versione 1.4.2, si è introdotto $.fn.delegate che è preferito a $. Fn.live.
5.11: Delegare un evento con $.fn.delegate
⤽
Copia codice

$('#myUnorderedList').delegate('li', 'click', function(e) {
    var $myListItem = $(this);
    // ...
});
5.12: Delegare un evento con $.fn.live
⤽
Copia codice

$('#myUnorderedList li').live('click', function(e) {
    var $myListItem = $(this);
    // ...
});
Scollegare Eventi Delegati
⤽
Se è necessario rimuovere gli eventi delegati, non lo si può semplicemente scollegare. Per questo, utilizzare il $.fn.undelegate per gli eventi connessi con $.fn.delegate, e $.fn.die per gli eventi connessi con $.fn.live. Come quando si effettua un legame, opzionalmente, è possibile passare il nome di una funzione legata.
5.13: Scollegare Eventi Delegati
⤽
Copia codice

$('#myUnorderedList').undelegate('li', 'click');
$('#myUnorderedList li').die('click');
Funzioni ausiliarie degli Eventi
⤽
jQuery fornisce due funzioni ausiliarie per lavorare con gli eventi:
$.fn.hover
⤽
Il metodo $.fn.hover permette passare una o due funzioni da eseguire quando si verificano gli eventi mouseenter e mouseleave. Se si passa una sola funzione, questa sarà eseguita in entrambi gli eventi, ma invece se si passano due, la prima sarà eseguita quando si verifica l’evento mouseenter, mentre la seconda sarà eseguita quando si verifica mouseleave.

Dalla versione 1.4 di jQuery, il metodo richiede due funzioni obbligatorie.
5.14: La funzione ausiliaria hover
⤽
Copia codice

$('#menu li').hover(function() {
    $(this).toggleClass('hover');
});
$.fn.toggle
⤽
Come il metodo precedente, $.fn.toggle riceve due o più funzioni, ogni volta che si verifica un evento, la funzione seguente nella lista verrà eseguita. In generale, $.fn.toggle viene utilizzata con solo due funzioni. Se si utilizzano più di due funzioni, fate attenzione, perché può essere difficile eseguire il debug del codice.
5.15: La funzione ausiliaria toggle
⤽
Copia codice

$('p.expander').toggle(
    function() {
        $(this).prev().addClass('open');
    },
    function() {
        $(this).prev().removeClass('open');
    }
);
Esercizi
⤽
⤽
Aprire il file /exercises/index.html dal browser. Eseguire ejericio utilizzando il file /exercises/js/inputHint.js o lavorare direttamente con Firebug. Il compito è quello di utilizzare etichetta di testo dell’elemento label e applicare un “suggerimento” nella casella di immissione testo. I passi da seguire sono:

  • Impostare il valore dell’elemento input uguale al valore dell’elemento label;
  • Aggiungere la classe “hint” all’elemento input;
  • Remuover l’elemento label;
  • Collegare un evento focus nell’elemento input per rimuovere il testo di suggerimento e la classe “hint”;
  • Collegare un evento blur nel input per ripristinare il testo di suggerimento e la classe “hint” nel caso in cui un testo non hintviene inserito.

Quali altre considerazioni si dovrebbero prendere in considerazione se si desidera applicare questa funzionalità a un sito vero e proprio?

Aggiungere una navigazione a schede
⤽
Aprire il file /exercises/index.html dal browser. Eseguire ejericio utilizzando il file /exercises/js/tabs.js o lavorare direttamente con Firebug. Il compito è quello di creare una navigazione a schede per gli elementi div.module. I passi sono da seguire sono:

  • Nascondere titti gli elementi div.module;
  • Creare una lista non ordinata prima del primo div.module per utilizzarla come schede;
  • Interagire con ogni div.module usando $.fn.each. Per ciascuna, utilizzare il testo dell’elemento h2 come testo per l’elemento della lista non ordinata; Interactuar con cada div utilizando $.fn.each.
  • Collegare un evento click per ogni elemento nella lista in modo che:
    • Visualizzare il div corrispondente e nascondere l’altro;
    • Aggiungere la classe “current” al ítem selezionato;
    • Rimuovere la classe “current” su l’altro item della lista;
  • Infine, mostrare la prima scheda.
[nextpage title=”Effetti”] Introduzione
⤽
Con jQuery, aggiungere effetti ad una pagina è facile. Questi effetti hanno una impostazione di default, ma si può anche fornire impostazioni personalizzate. E’ anche possibile creare animazioni impostando valori di proprietà specifici del CSS.
Per la documentazione completa sui diversi tipi di effetti si possono visitare http://api.jquery.com/category/effects/.
Effetti incorporati nella Libreria
⤽
Gli effetti più comuni sono già incorporati nella libreria sotto forma di metodi:

  •  $.fn.show Visualizza l’elemento selezionato.
  •  $.fn.hide Nasconde l’elemento selezionato.
  •  $.fn.fadeIn In forma animata, modifica l’opacità dell’elemento selezionato al 100%
  •  $.fn.fadeOut In forma animata, modifica l’opacità dell’elemento selezionato al 0%
  •  $.fn.slideDown Consente di visualizzare l’elemento selezionato con un movimento a scorrimento verticale.
  •  $.fn.slideUp Nasconde l’elemento selezionato con un movimento a scorrimento verticale.
  •  $.fn.slideToggle Visualizza o nasconde l’elemento selezionato con un movimento a scorrimento verticale, a seconda che l’elemento sia correntemente visibile o meno.
  • 6.1: Utilizzo di base di un effetto incorporato
    ⤽
    Copia codice
    
    $('h1').show();
    
    Cambiare la durata degli effetti
    ⤽
    Con l’eccezione di $.fn.show e $.fn.hide, tutti i metodi hanno una durata predefinita dell’animazione di 400ms. Questo valore è possibile cambiarlo.
    6.2: Impostare la durata degli effetti
    ⤽
    Copia codice
    
    $('h1').fadeIn(300);      // dissolvenza in 300ms
    $('h1').fadeOut('slow');  // utilizzo di una definizione di velocità interna
    
    jQuery.fx.speeds
    ⤽
    jQuery è un oggetto che contiene in jQuery.fx.speeds la velocità predefinita per la durata di un effetto, così come i valori per le definizioni “slow” e “fast”.
    Copia codice
    
    speeds: {
        slow: 600,
        fast: 200,
        // Velocità predefinita
        _default: 400
    }
    
    Pertanto, è possibile sovrascrivere o aggiungere nuovi valori all’oggetto. Per Esempio, quando si vuole cambiare l’effetto predefinito o aggiungere una velocità personalizzata.
    6.3: Aumentare la velocità con jQuery.fx.speeds
    ⤽
    Copia codice
    
    jQuery.fx.speeds.blazing = 100;
    jQuery.fx.speeds.turtle = 2000;
    
    Eseguire un'azione quando un effetto è stato eseguito
    ⤽
    Spesso, si desidera eseguire l’azione una volta che l’animazione sia finita — perché se si esegue l’azione prima che l’animazione sia terminata, possono alterare la qualità degli effetti o influenzare gli elementi che ne fanno parte. [Definizione: Le funzioni di retrochiamata (callback functions in inglese) forniscono un modo per eseguire codice quando un evento si è concluso.] In questo caso, l’evento che risponderà alla funzione sarà la conclusione dell’animazione. All’interno della funzione di ritorno, la parola chiave this fa riferimento all’elemento cui è stato eseguito l’effetto, e come accade con gli eventi, è possibile trasformarlo in un oggetto jQuery utilizzando $(this).
    6.4: Eseguire del codice quando un'animazione è completata
    ⤽
    Copia codice
    
    $('div.old').fadeOut(300, function() { $(this).remove(); });
    
    Si noti che se la selezione non restituisce alcun elemento, la funzione non potrà mai essere eseguita. Questo problema può essere risolto controllando se la selezione restituisce un oggetto; e in caso contrario eseguire la funzione di retrochiamata immediatamente.
    6.5: Eseguire una funzione di retrochiamata, anche se non c'è nessun elemento da animare
    ⤽
    Copia codice
    
    var $thing = $('#nonexistent');
    var cb = function() {
        console.log('realizzato!');
    };
    if ($thing.length) {
        $thing.fadeIn(300, cb);
    } else {
        cb();
    }
    
    Effetti personalizzati con $.fn.animate
    ⤽
    Le animazioni sono possibili realizzarle utilizzando il metodo $.fn.animate. Questo metodo permette realizzare un’animazione impostando i valori alle proprietà CSS o cambiando il loro valore corrente.
    6.6: Effetti personalizzati con $.fn.animate
    ⤽
    Copia codice
    
    $('div.funtimes').animate(
        {
            left : "+=50",
            opacity : 0.25
        },
        300, // durata
        function() { console.log('done!'); // retrochiamata
    });
    
    Le proprietà relative al colore non possono essere animate con il metodo $.fn.animate, ma è possibile farlo attraverso l’estensione color plugin.
    Più tardi nel libro si discuterà l’uso delle estensioni.
    Easing
    ⤽
    [Definizione: Il concetto di Easing descrive il modo come un effetto si verifica – cioè, se la velocità durante l’animazione è costante o meno]. JQuery comprende solo due metodi di allentamento: swing e linear. Per ulteriori transizioni naturali nelle animazioni, ci sono molte estensioni che lo permettono.

    Dalla versione 1.4 della libreria, è possibile impostare il tipo di transizione per ogni proprietà utilizzando il metoso $.fn.animate.
    6.7: Transizione easing per ogni proprietà

    ⤽
    Copia codice
    
    $('div.funtimes').animate(
        {
            left : [ "+=50", "swing" ],
            opacity : [ 0.25, "linear" ]
        },
        300
    );
    
    Gestione degli Effetti
    ⤽
    jQuery offre diversi strumenti per gestire le animazioni.
    $.fn.stop
    ⤽
    Interrompe le animazioni che sono in esecuzione sull’elemento selezionato.
    $.fn.delay
    ⤽
    Attende un periodo di tempo specificato prima di eseguire l’animazione successiva.
    Copia codice
    
    $('h1').show(300).delay(1000).hide(300);
    
    jQuery.fx.off
    ⤽
    Se il valore è vero (true), non ci saranno transizioni per le animazioni e agli elementi si stabilirà lo stato finale dell’animazione. Questo metodo può essere particolarmente utile quando si lavora con i vecchi browser.
    Esercizi
    ⤽
    Visualizzare il testo nascosto
    ⤽
    Aprire il il file /exercises/index.html nel browser web. Eseguire ejericio utilizzando il file /exercises/js/blog.js. Il compito è quello di aggiungere un po ‘interattività alla sezione blog della pagina:

    • Cliccando su uno qualsiasi dei titolari del div #blog, si dovrebbe visualizzare il testo con un effetto scorrevole;
    • Facendo clic su un altro titolo, si dovrebbe nascondere il paragrafo mostrato con un effetto di scorrimento e mostrare di nuovo il paragrafo corrispondente anche con un effetto di scorrimento.

    Suggerimento: Non dimenticare di usare il selettore :visible.

    Creare una Menù a tendina (Drop Down)
    ⤽
    Aprire il file /exercises/index.html nel browser web. Eseguire ejericio utilizzando il file /exercises/js/navigation.js. Il compito è quello di visualizzare le voci di menu in cima alla pagina:

    • Passando il mouse su una voce del menu, si dovrebbe visualizzare un sottomenu se esiste;
    • Quando non è posizionato sopra un item, il sottomenu si dovrebbe nascondere.

    Per fare questo, utilizzare il metodo $.fn.hover per aggiungere o rimuovere una classe al sottomenu per controllare se deve essere nascosto o visibile (Il file /exercises/css/styles.css include una classe “hover” per questo scopo).

    Creare un Slideshow
    ⤽
    Aprire il file /exercises/index.html nel browser web. Eseguire l’esercizio utilizzando il file /exercises/js/slideshow.js. Il compito è quello di aggiungere uno slideshow alla pagina con JavaScript.

    • Spostare l’elemento #slideshow alla parte superiore della pagina;
    • Scrivere un codice per la visualizzazione degli items in maniera ciclica, mostrando un item per alcuni secondi, poi nasconderlo con un effetto fade out e mostrare il seguente item con l’effetto di dissolvenza fade in;
    • Una volta raggiunto l’ultimo elemento della lista, ricominciare con il primo;

    Per una sfida più grande, creare un area di navigazione sotto lo slideshow che mostra quante immagini ci sono e su quale si trova (suggerimento: $.fn.prevAll può essere utile).

    [nextpage title=”Ajax”] Introduzione
    ⤽
    Il metodo XMLHttpRequest (XHR) consente ai browser di comunicare con il server senza ricaricare la pagina. Questo metodo, noto anche come Ajax (Asincrono JavaScript e XML, in inglese Asynchronous JavaScript and XML), consente alle applicazioni di creare interattività.

    Le richieste Ajax vengono eseguite dal codice JavaScript, il quale invia una richiesta a un URL e quando riceve una risposta, una funzione di ritorno può essere eseguita il quale riceve come argomento la risposta del server e ne fa qualcosa con questa. Visto che la risposta è asincrona, il resto del codice dell’applicazione continua a funzionare, quindi è imperativo che una funzione di ritorno venga eseguita per gestire la risposta.

    Attraverso vari metodi, jQuery fornisce il supporto per AJAX, che consente astrarre le differenze che possono esistere tra i browser. I metodi in questione sono $.get(), $.getScript(), $.getJSON(), $.post() e $().load().

    Sebbene la definizione di Ajax ha la parola “XML”, la maggior parte delle applicazioni non utilizzare questo formato per il trasporto dei dati, ma al suo posto utilizza testo formato HTML o informazioni in JSON (JavaScript Object Notation).

    In generale, l’Ajax non funziona in domini diversi. Tuttavia, ci sono delle eccezioni, come i servizi che forniscono informazioni in formato JSONP (JSON with Padding), che permettono funzionalità limitate in domini diversi.

    Concetti chiave
    ⤽
    L’uso corretto dei metodi di Ajax richiede in primo luogo la comprensione di alcuni concetti chiave.
    GET vs. POST
    ⤽
    I due metodi HTTP più comuni per l’invio di una richiesta a un server sono GET e POST. E ‘importante capire l’uso di ciascuno.

    Il metodo GET dovrebbe essere utilizzato per operazioni non distruttive – cioè, operazioni in cui si sta “ottenendo” dati dal server, e non “modificando”. Per Esempio, una query per una ricerca potrebbe essere una richiesta GET. D’altra parte, le richieste GET possono essere memorizzate nella cache del browser e può generare comportamenti imprevedibili se non attesi. In generale, le informazioni inviate al server, vengono inviati in una stringa di dati (in inglese query string).

    Il metodo POST dovrebbe essere utilizzato per operazioni distruttive – cioè operazioni in cui vengono incorporate informazioni nel server. Per Esempio, quando un utente salva un articolo in un blog, questa azione dovrebbe usare POST. D’altra parte, con questo tipo di metodo non viene memorizzato nella cache del browser. Inoltre, una stringa di query può essere parte della URL, ma le informazioni tendono ad essere inviate separatamente.

    Tipi de Dati
    ⤽
    In generale, jQuery ha bisogno alcune istruzioni sul tipo di informazioni da ricevere quando si effettua una richiesta Ajax. In alcuni casi, il tipo di dati è specificato dal nome del metodo, ma in altri casi dovrebbe essere specificato come perte della configurazione del metodo:
    text
    ⤽
    Per il trasporto di semplici stringhe.
    html
    ⤽
    Per il trasporto di blocchi di codice in HTML che verranno inseriti nella pagina.
    script
    ⤽
    Per aggiungere un nuovo script con codice JavaScript alla pagina.
    json
    ⤽
    Per trasportare le informazioni in formato JSON, il quale può includere stringhe, array e oggetti.

    Dalla versione 1.4 della libreria, se l’informazione JSON non è correttamente formattata, la richiesta potrebbe non riuscire. Visita http://json.org per i dettagli sulla corretta formattazione dei dati JSON.

    Si consiglia di utilizzare i meccanismi che possiede il linguaggio lato server per generare le informazioni in JSON.

    jsonp
    ⤽
    Per trasportare le informazioni JSON da un dominio all’altro.
    xml
    ⤽
    Per trasportare le informazioni in formato XML.
    Nonostante i diversi tipi di dati che possono essere utilizzati, è raccomandato utilizzare il formato JSON, dal momento che è molto flessibile, consentendo per esempio, inviare al tempo stesso informazioni piatte e HTML.
    Asincronismo
    ⤽
    Perché, per impostazione predefinita, le chiamate Ajax sono asincrone, la risposta del server non è immediatamente disponibile. Per ssempio, il seguente codice non dovrebbe funzionare:
    Copia codice
    
    var response;
    $.get('foo.php', function(r) { response = r; });
    console.log(response); // undefined - indefinito!
    
    Invece, è necessario specificare una funzione di ritorno, questa funzione verrà eseguita quando la richiesta si sia conclusa correttamente in quanto è allora che la risposta del server è pronta.
    Copia codice
    
    $.get('foo.php', function(response) { console.log(response); });
    
    Politiche di Stessa Origine e JSONP
    ⤽
    In generale, le richieste Ajax sono limitati a usare lo stesso protocollo (http o https), la stessa porta e lo stesso dominio di origine. Questa limitazione non si applica agli script caricati tramite i metodi di jQuery Ajax.

    L’altra eccezione è quando si fa una richiesta di riceverà una risposta in formato JSONP. In questo caso, il fornitore della risposta dovrebbe rispondere alla richiesta con uno script che può essere caricato utilizzando il tag <script>, evitando così la limitazione ad effettuare richieste dallo stesso dominio. Questa risposta avrà le informazioni richieste, contenuta in una funzione.

    Ajax e Firebug
    ⤽
    Firebug (o l’ispettore WebKit che viene in Chrome o Safari) sono strumenti essenziali per lavorare con le richieste Ajax, giacché è possibile osservare dalla scheda console di Firebug (o andando in Risorse > Pannello XHR dalla finestra di ispezione Webkit) e vedere i dettagli di queste richieste. Se qualcosa non va a buon fine quando si lavora con l’Ajax, questo è il primo posto dive si dovrebbe andare per sapere quale è il problema.
    Metodi Ajax de jQuery
    ⤽
    Come indicato sopra, jQuery ha diversi metodi per lavorare con Ajax. Tuttavia, tutti si basano sul metodo $.ajax, quindi, la sua comprensione è obbligatoria. Di seguito si spiegherà il metodo e poi s’indicherà un breve riassunto sugli altri metodi.

    È generalmente preferibile utilizzare il metodo $.ajax piuttosto che altri, visto che offre più funzionalità e la sua configurazione è molto comprensibile.
    $.ajax

    ⤽
    Il metodo $.ajax è configurato attraverso un oggetto che contiene tutte le istruzioni che necessita jQuery per completare la richiesta. Questo metodo è particolarmente utile perché offre la possibilità di specificare azioni se la richiesta sia riuscita o meno. Inoltre, essendo impostato attraverso un oggetto, è possibile impostare le proprietà separatamente, rendendo più facile il riutilizzo del codice. È possibile visitare http://api.jquery.com/jQuery.ajax/ per consultare la documentazione sulle opzioni disponibili nel metodo.
    7.1: Utilizzare il metodo $.ajax
    ⤽
    Copia codice
    
    $.ajax({
        // l'URL per la richiesta
        url : 'post.php',
        // invio di informazioni
        // (è anche possibile utilizzare una stringa di dati)
        data : { id : 123 },
        // specificare se si tratta di una richiesta POST o GET
        type : 'GET',
        // il tipo di informazioni
        // che ci si attende come risposta
        dataType : 'json',
        // codice da eseguire se la richiesta viene accettata;
        // la risposta è passata come argomento alla funzione
        success : function(json) {
            $('<h1/>').text(json.title).appendTo('body');
            $('<div class="content"/>')
                .html(json.html).appendTo('body');
        },
        // codice da eseguire se la richiesta fallisce;
        // sono passati come argomenti alla funzione
        // l'oggetto della petizione in codice grezzo
        // e lo stato della richiesta
        error : function(xhr, status) {
            alert('Spiacente, c\'è stato un problema!');
        },
        // codice da eseguire indipendentemente dal
        // fatto se la richiesta riesca.
        complete : function(xhr, status) {
            alert('Richiesta fatta!');
        }
    });
    
    Un chiarimento sul parametro dataType: se il server restituisce informazioni differenti dal formato specificato, il codice fallirà e la ragione perché lo faccia non è sempre chiara, perché la risposta HTTP non mostrerà alcun errore. Quando si lavora con le richieste Ajax, assicurarsi che il server invii il tipo di informazioni che si richiede e verificare che il Content-type sia esattamente al tipo di dati richiesti. Per esempio, per le informazioni in formato JSON, il Content-type dovrebbe essere application/json.
    Opzioni del metodo $.ajax
    ⤽
    Il metodo $.Ajax ha molte opzioni di configurazione, ed è proprio questa caratteristica che lo rende un metodo molto utile. Per un elenco completo delle opzioni disponibili, consultare http://api.jquery.com/jQuery.ajax/; le seguenti sono le più comuni:
    async
    ⤽
    Imposta se la richiesta è asincrona o meno. Di default il valore è true. È necessario essere consapevoli che se l’opzione è impostata su false, la richiesta bloccherà l’esecuzione di altri codici fino a quando la richiesta sia completata.
    cache
    ⤽
    Impostare se la richiesta viene memorizzata nella cache del browser web. Di default è true per tutti i dataType fatta eccezione per “script” e “jsonp”. Quando il valore è false, si aggiunge una stringa anti-cache alla fine della URL della richiesta.
    complete
    ⤽
    Imposta una funzione di retrochiamata che viene eseguita quando la richiesta sia stata completata, anche se ha fallito. La funzione riceve come argomenti l’oggetto della richiesta in grazzo e il codice di status della stessa richiesta.
    context
    ⤽
    Imposta l’ambito in cui vengono eseguite le funzioni di retrochiamata. (per Esempio definisce il significato di this all’interno delle funzioni). Di default this fa riferimento all’oggetto passato in origine al metodo $.ajax.
    data
    ⤽
    Consente di impostare le informazioni da inviare al server. Questo può essere un oggetto come una stringa di dati (per esempio foo=bar&baz=bim).
    dataType
    ⤽
    Consente di impostare il tipo di informazioni da ricevere in risposta dal server. Se nessun valore è specificato, per impostazione predefinita, jQuery controlla il tipo MIME che ha la risposta.
    error
    ⤽
    Imposta una funzione di retrociamata da eseguire se si tratta di un errore nella petizione. Detta funzione prende come argomenti l’oggetto della richiesta grezza e il codice di status della richiesta stessa.
    jsonp
    ⤽
    Imposta il nome della funzione di retrochiamata da inviare quando viene effettuata una richiesta JSONP. Di default il nome è “callback”.
    success
    ⤽
    Imposta una funzione da eseguire se la richiesta ha avuto successo. Questa funzione prende come argomenti le informazioni della richiesta (convertito in un oggetto JavaScript nel caso sia dataType o JSON), lo status della stessa e l’oggetto della petizione in grezzo.
    timeout
    ⤽
    Imposta il tempo in millisecondi da considerare per una richiesta non riuscita.
    traditional
    ⤽
    Se il suo valore è true, viene utilizzato lo stile di serializzazione di dati utilizzati nelle versioni di jQuery prima della 1.4. Per maggiori dettagli visitate http://api.jquery.com/jQuery.param/.
    type
    ⤽
    Il tipo di richiesta, “POST” o “GET”. Di default il suo valore è “GET”. Altre tipi di richieste possono anche essere utilizzati come (come PUT e DELETE), ma possono non essere supportati da tutti i browser.
    url
    ⤽
    Imposta l’URL in cui è presentata la richiesta.
    L’opzione url è obbligatoria per il metodo $.ajax.
    Metodi convenienti
    ⤽
    Se non si desidera utilizzare il metodo $.ajax, e non necessita manipolare o gestire gli errori, esistono altri metodi più adatti per le richieste Ajax (sebbene, come notato in precedenza, questi sono basati al metodo $.ajax con valori prestabiliti di configurazione).
    I metodi che fornisce la libreria sono:
    $.get
    ⤽
    Fa una richiesta GET a un URL previsto.
    $.post
    ⤽
    Fa una richiesta POST a un URL previsto.
    $.getScript
    ⤽
    Aggiunge uno script alla pagina.
    $.getJSON
    ⤽
    Fa una richiesta GET a un URL previsto e si aspetta che un dato JSON venga restituito.
    url
    ⤽
    L’URL in cui si farà la richiesta. Il suo valore è obbligatorio.
    data
    ⤽
    Le informazioni inviate al server. Il suo valore è facoltativo e può essere sia un oggetto o una stringa di dati (per esempio foo=bar&baz=bim).

    Le informazioni inviate al server. Il suo valore è facoltativo e può essere sia un oggetto o una stringa di dati (per esempio foo=bar&baz=bim).
    success callback
    ⤽
    Una funzione opzionale che viene eseguita in caso la richiesta ha avuto successo. Questa funzione prende come argomenti le informazioni della richiesta e l’oggetto grezzo della petizione.
    data type
    ⤽
    Il tipo di dati che dovrebbero essere ricevuti dal server. Il suo valore è facoltativo.

    Questa opzione è applicabile solo per i metodi dove non sia specificato il tipo di dati nel nome dello stesso metodo.
    7.2: Utilizzare metodi appropriati nelle richieste Ajax
    ⤽
    Copia codice
    
    // ottiene il testo piano o html
    $.get('/users.php', { userId : 1234 }, function(resp) {
        console.log(resp);
    });
    // aggiunge uno script alla pagina e quindi
    // esegue la funzione specificata
    $.getScript('/static/js/myScript.js', function() {
        functionFromMyScript();
    });
    // ottiene i dati in formato JSON dal server
    $.getJSON('/details.php', function(resp) {
        $.each(resp, function(k, v) {
            console.log(k + ' : ' + v);
        });
    });
    
    $.fn.load
    ⤽
    Il metodo $.fn.load è l’unico che può essere chiamato da una selezione. Questo metodo ottiene il codice HTML da un URL e riempire gli elementi selezionati con le informazioni ottenute. In concomitanza con l’URL, è possibile specificare facoltativamente un selettore, il quale otterrà il codice specificato in questa selezione.
    7.3: Utilizzare il metodo $.fn.load per riempire un elemento
    ⤽
    Copia codice
    
    $('#newContent').load('/foo.html');
    
    7.4: Utilizzare il metodo $.fn.load per riempire un elemento basato su una selezione.
    ⤽
    Copia codice
    
    $('#newContent').load('/foo.html #myDiv h1:first', function(html) {
      alert('Contenuto aggiornato!');
    });
    
    Ajax e Forms
    ⤽
    Le funzionalità di jQuery con Ajax possono essere particolarmente utili per lavorare con i forms. Per esempio, il plugin jQuery Form Plugin è una estensione per aggiungere le funzionalità di Ajax sui forms. Ci sono due metodi che bisogna tenere conto quando si lavora con $.ajax sui forms: $.fn.serialize e $.fn.serializeArray.
    7.5: Trasformare le informazioni da una form in una stringa di dati
    ⤽
    Copia codice
    
    $('#myForm').serialize();
    
    7.6: Creare un array di oggetti che contengono informazioni da un form
    ⤽
    Copia codice
    
    $('#myForm').serializeArray();
    // crea una struttura come questa:
    [
        { name : 'field1', value : 123 },
        { name : 'field2', value : 'hello world' }
    ]
    
    Lavorare con JSONP
    ⤽
    In tempi recenti, l’introduzione di JSONP, ha permesso la creazione di applicazioni ibride di contenuti. Molti siti offrono importanti offrono JSONP come servizio di informazione, cui si accede attraverso un’API (Application programming interface in inglese) predefinita. Un particolare servizio che fornisce informazioni in formato JSONP è Yahoo! Query Language, che lo utilizza per ottenere, per esempio, notizie sui gatti:
    7.7: Usare YQL e JSONP
    ⤽
    Copia codice
    
    $.ajax({
        url : 'http://query.yahooapis.com/v1/public/yql',
        // viene aggiunto come parametro il nome della funzione
        // di ritorno, come specificato nel servizio di YQL
        jsonp : 'callback',
        // si indica jQuery che è atteso informazioni
        // in formato JSONP
        dataType : 'jsonp',
        // si indica al servizio di YQL quale è l'informazione
        // che si desidera e che la si vuole in formato JSON
        data : {
            q : 'select title,abstract,url from search.news where query="cat"',
            format : 'json'
        },
        // si esegue una funzione se
        // la richiesta è andata a buon fine
        success : function(response) {
            console.log(response);
        }
    });
    
    jQuery si occupa di risolvere tutti gli aspetti complessi della richiesta JSONP. Tutto quello che si deve fare è specificare il nome della funzione di ritorno (in questo caso “callback”, come da specifica YQL) e il risultato finale sarà come una normale richiesta Ajax.
    Eventi Ajax
    ⤽
    Spesso si desidera eseguire una funzione quando una petizione si avvia o finisca, come per esempio, mostrare o nascondere un indicatore. Invece di definire queste funzioni all’interno di ogni richiesta, jQuery offre la possibilità di vincolare gli eventi Ajax agli elementi selezionati. Per un elenco completo degli eventi Ajax, è disponibile la pagina http://docs.jquery.com/Ajax_Events.
    7.8: Mostra/Nascondi un indicatore utilizzando Eventi di Ajax
    ⤽
    Copia codice
    
    $('#loading_indicator')
        .ajaxStart(function() { $(this).show(); })
        .ajaxStop(function() { $(this).hide(); });
    
    Esercizi
    ⤽
    Caricare contenuto esterno
    ⤽
    Open the file /exercises/index.html in your browser. Use the file /exercises/js/load.js. Your task is to load the content of a blog item when a user clicks on the title of the item.

    • Creare un elemento div dopo il titolo di ogni titolo di articolo del blog e salvare un riferimento ad essi nell’elemento titolo utilizzando $.fn.data.
    • Vinculare un evento click al titolo, il quale utilizzerà il metodo $.fn.load per caricare in ogni div creato il contenuto appropriato dal file /exercises/data/blog.html. Non dimenticare di disattivare il comportamento predefinito dell’evento click.

    Da notare che ogni titolo di articolo del blog in index.html include un link a questo articolo. Sfruttare l’attributo href di ogni link per ottenere il contenuto particolare di blog.html. Dopo aver ottenuto il valore dell’attributo, utilizzare il seguente form per elaborare le informazioni e convertirla in un selettore per l’uso in combinazione con $.fn.load:

    Copia codice
    
    var href = 'blog.html#post1';
    var tempArray = href.split('#');
    var id = '#' + tempArray[1];
    
    Ricordatevi di usare console.log per assicurarsi che si sta facendo la cosa giusta.
    Carricare contenuto utilizzando JSON
    ⤽
    Aprire il file /exercises/index.html nel browser web. Eseguire ejericio utilizzando il file /exercises/js/specials.js. Il compito è quello di mostrare i dati dell’utente in un particolare giorno quando viene selezionato dal menù a discesa.

    • Aggiungere un elemento div dopo il form all’interno dell’elemento #specials; sarà lì il luogo dove si metteranno le informazioni da ottenere.
    • Vincolare l’evento change sull’elemento select; quando si apporta una modifica nella selezione, inviare una richiesta Ajax a /exercises/data/specials.json.
    • Quando la richiesta restituisce una risposta, utilizzare il valore selezionato nella select (suggerimento: $.fn.val) per trovare le informazioni appropriate nella risposta JSON.
    • Aggiungere un po’ di HTML con le informazioni ottenute nel div creato in precedenza.
    • Infine rimuovere il pulsante di invio (submit) del form.

    Notare che ogni volta che cambia la selezione, si esegue una richiesta Ajax. Come si potrebbe modificare il codice per eseguire solo una richiesta e salvare le informazioni per trarre vantaggio quando si torna a modificare la selezione?

    [nextpage title=”Estensioni”] Cos'è un estensione?
    ⤽
    Un’estensione di jQuery è semplicemente un nuovo metodo da utilizzare per estendere il prototipo (prototype) dell’oggetto jQuery. Quando si estende il prototipo, tutti gli oggetti jQuery ereditano i metodi aggiunti. Pertanto, quando viene effettuata una chiamata jQuery(), viene creato un nuovo oggetto jQuery con tutti i metodi ereditati.

    Lo scopo di un’estensione è di eseguire un’azione utilizzando un insieme di elementi, proprio come fanno, per esempio, i metodi fadeOut o addClass della libreria.

    È possibile effettuare le proprie estensioni e usarle privatamente nel progetto o è anche possibile pubblicarli in modo che altri potranno usufruire.

    Come creare di una estensione di base
    ⤽
    Il codice per creare un’estensione di base è il seguente:
    Copia codice
    
    (function($){
        $.fn.myNewPlugin = function() {
            return this.each(function(){
                // fare qualcosa
            });
        };
    }(jQuery));
    
    L’estensione del prototipo dell’oggetto jQuery si verifica nella seguente riga:
    Copia codice
    
    $.fn.myNewPlugin = function() { //...
    Il quale è racchiusa in una funzione auto-eseguibile
    Copia codice
    
    (function($){
        //...
    }(jQuery));
    
    Questo ha il vantaggio di creare un’ambito “privato”, che consente di utilizzare il simbolo del dollaro, senza timore che un’altra libreria utilizzi anche lo stesso segno.

    Per ora, internamente l’estensione è:

    Copia codice
    
    $.fn.myNewPlugin = function() {
        return this.each(function(){
            // fare qualcosa
        });
    };
    
    In esso, la parola chiave this si riferisce all’oggetto jQuery in cui è chiamata l’estensione.
    Copia codice
    
    var somejQueryObject = $('#something');
    $.fn.myNewPlugin = function() {
        alert(this === somejQueryObject);
    };
    somejQueryObject.myNewPlugin();
    // mostra un avviso con  'true'
    
    L’oggetto jQuery di solito contiene diversi riferimenti agli elementi DOM, ed è per questo che sono spesso definiti come una collezione.

    Per interagire con l’insieme di elementi, è necessario fare un ciclo, che è facilmente ottenibile con il metodo each():

    Copia codice
    
    $.fn.myNewPlugin = function() {
        return this.each(function(){
        });
    };
    
    Come gli altri metodi, each() restituisce un oggetto jQuery, permettendo il concatenamento dei metodi utilizzati ($(…).css().attr()…). Per evitare di rompere questa convenzione, l’estensione da creare dovrà ritornare l’oggetto this per consentire di continuare con la catena. Di seguito è riportato un piccolo esempio:
    Copia codice
    
    (function($){
        $.fn.showLinkLocation = function() {
            return this.filter('a').each(function(){
                $(this).append(
                    ' (' + $(this).attr('href') + ')'
                );
            });
        };
    }(jQuery));
    // Esempio di utilizzo:
    $('a').showLinkLocation();
    
    L’estensione modificherà tutti i link all’interno della collezione di oggetti e aggiungerà il valore attributo del suo attributo href tra parentesi.
    Copia codice
    
    <!-- Prima che l'estensione sia chiamata: -->
    <a href="page.html">Foo</a>
    <!-- Dopo che l'estensione sia chiamata: -->
    <a href="page.html">Foo (page.html)</a>
    
    È anche possibile ottimizzare l’estensione:
    Copia codice
    
    (function($){
        $.fn.showLinkLocation = function() {
            return this.filter('a').append(function(){
                  return ' (' + this.href + ')';
            });
        };
    }(jQuery));
    
    Il metodo append permette specificare una funzione di ritorno (callback), e il valore di ritorno determinerà ciò che verrà aggiunto ad ogni elemento. Si noti anche che non viene utilizzato il metodo attr, perché l’API nativa del DOM consente un facile accesso alla proprietà href.

    Di seguito è riportato un altro eEsempio di estensione. In questo caso, non è tenuto a fare un ciclo su ogni elemento perché la funzionalità è delegata direttamente in un altro metodo di jQuery:

    Copia codice
    
    (function($){
        $.fn.fadeInAndAddClass = function(duration, className) {
            return this.fadeIn(duration, function(){
                $(this).addClass(className);
            });
        };
    }(jQuery));
    // Esempio di utilizzo:
    $('a').fadeInAndAddClass(400, 'finishedFading');
    
    Individuare e valutare estensioni
    ⤽
    Uno degli aspetti più popolari di jQuery è la diversità di estensioni che esistono.

    Tuttavia, la qualità può variare notevolmente tra le estensioni. Molti sono ampiamente testati e ben mantenute, ma alcuni sono state create in fretta e poi ignorate, senza seguire le buone prassi.

    Google è il miglior strumento per trovare le estensioni (anche se il team di jQuery sta lavorando per migliorare la sua repository di estensioni). Una volta trovata l’estensione, si consiglia di consultare la newsletter di jQuery o il canale IRC #jquery per ottenere il parere di altri circa l’estensione.

    Assicurarsi che l’estensione sia ben documentata, e che offono esempi di utilizzo. Stare attenti anche con le estensioni che fanno più del necessario, queste possono arrivare a sovraccaricare la pagina. Per ulteriori suggerimenti su come individuare un’estensione mediocre, è possibile leggere l’articolo (in inglese) I segni di un plugin per jQuery scritto male da Remy Sharp (http://remysharp.com/2010/06/03/signs-of-a-poorly-written-jquery-plugin/).

    Dopo aver selezionato l’estensione, è necessario aggiungerla alla pagina. In primo luogo, scaricare l’estensione, scompattarla (se necessario) e spostarla nella cartella dell’applicazione. Infine inserirla utilizzando l’elemento script (dopo l’inclusione di jQuery).

    Scrivere estensioni
    ⤽
    A volte si vuole fare una funzionalità disponibile in tutto il codice, per esempio, un metodo che possa essere chiamato da una selezione il quale realizzi una serie di operazioni.

    La maggior parte delle estensioni sono metodi creati all’interno del namespace $.fn. jQuery assicura che un metodo chiamato sull’oggetto jQuery sia in grado di accedere a detto oggetto attraverso this. In contrasto, l’estensione dovrebbe garantire per restituire lo stesso oggetto ricevuto (salvo diversa indicazione).

    Di seguito si mostra un esempio:
    8.1: Creare una estensione per aggiungere e rimuovere una clesse in un elemento quando accade l'evento hover

    ⤽
    Copia codice
    
    // definizione dell'estensione
    (function($){
        $.fn.hoverClass = function(c) {
            return this.hover(
                function() { $(this).toggleClass(c); }
            );
        };
    })(jQuery);
    // utilizzare l'estensione
    $('li').hoverClass('hover');
    
    Per ulteriori informazioni sullo sviluppo di estensioni, vedere l’articolo (in inglese) A Plugin Development Pattern di Mike Alsup.
    In questo articolo, si sviluppa un’estensione chiamata $.fn.hilight, che fornisce un supporto per l’estensione metadata (se presente) e fornisce un metodo decentrato per impostare opzioni globali o istanze dell’estensione.
    8.2: Il modello di sviluppo di estensioni per jQuery spiegato da Mike Alsup
    ⤽
    Copia codice
    
    //
    // creare una chiusura
    //
    (function($) {
      //
      // definizione dell'estensione
      //
      $.fn.hilight = function(options) {
        debug(this);
        // generazione delle opzioni principali
        // prima di interagire
        var opts = $.extend({}, $.fn.hilight.defaults, options);
        // ittera e riformatta ogni elemento
        return this.each(function() {
          $this = $(this);
          // generazione delle opzioni specifiche
          // per ogni elemento
          var o = $.meta ? $.extend({}, opts, $this.data()) : opts;
          // aggiornamento degli stili per ogni elemento
          $this.css({
            backgroundColor: o.background,
            color: o.foreground
          });
          var markup = $this.html();
          // si chiama la funzione per la formattazione
          markup = $.fn.hilight.format(markup);
          $this.html(markup);
        });
      };
      //
      // funzione privata per la depurazione
      //
      function debug($obj) {
        if (window.console && window.console.log)
          window.console.log('hilight selection count: ' + $obj.size());
      };
      //
      // definire ed esporre la funzione di formattazione
      //
      $.fn.hilight.format = function(txt) {
        return '<strong>' + txt + '</strong>';
      };
      //
      // opzioni predefinite
      //
      $.fn.hilight.defaults = {
        foreground: 'red',
        background: 'yellow'
      };
    //
    // fine della chiusura
    //
    })(jQuery);
    
    Scrivere estensioni con mantenimento di stato utilizzando Widget Factory di jQuery UI
    ⤽
    Questa sezione è basata, con il permesso dell’autore, dall’articolo Building Stateful jQuery Plugins di Scott Gonzalez.

    Mentre la maggior parte delle estensioni per jQuery sono esenti da manutenzione dello stato (stateless in inglese) – vale a dire, estensioni che vengono eseguiti su un solo elemento, essendo l’unica interazione – c’è un grande numero di funzionalità che non si utilizzano nello schema di base dove si sviluppano estensioni.

    Per colmare questa lacuna, jQuery UI (jQuery User Interface) ha implementato un sistema più avanzato di estensioni. Questo sistema permette di gestire gli stati e ammette più funzioni da essere esposte in una singola estensione. Questo sistema è chiamato widget factory e fa parte della versione 1.8 di jQuery UI attraverso jQuery.widget, ma può essere utilizzato anche senza dipendere da jQuery UI.

    Per dimostrare le capacità di widget factory, si creerà un’estensione che avrà come funzionalità sarà barra di avanzamento.

    Per ora, l’estensione permetterà solo d’impostare il valore della barra di avanzamento una volta. Questo sarà fatto chiamando jQuery.widget con due parametri: il nome dell’estensione da creare e un oggetto letterale contenente le funzioni supportate. Quando l’estensione sarà chiamata, una sua istanza verrà creata e tutte le funzioni si eseguiranno nel contesto di tale istanza.

    Ci sono due differenze importanti rispetto a una estensione standard per jQuery: in primo luogo, il contesto è un oggetto, non un elemento DOM; in secondo luogo, il contesto è sempre un unico oggetto, mai una collezione.
    8.3: Una semplice estensione con mantenimento dello stato utilizzando widget factory di jQuery UI

    ⤽
    Copia codice
    
    $.widget("nmk.progressbar", {
        _create: function() {
            var progress = this.options.value + "%";
            this.element
                .addClass("progressbar")
                .text(progress);
        }
    });
    
    Il nome dell’estensione deve contenere uno spazio di nomi, in questo caso viene utilizzato nmk. Gli spazi di nomi sono limitati ad un solo livello di profondità – il che significa, per esempio, che non poò essere utilizzato nmk.foo. Come si può vedere nell’esempio, widget factory fornisce due proprietà da utilizzare. La prima, this.element è un oggetto jQuery che contiene esattamente un elemento. Nel caso in cui l’estensione venga eseguita su più di una voce, un’istanza separata dell’estensione verrà creata per ogni elemento e ciascuno avrà il suo propria this.element. La seconda proprietà, this.options, è un insieme di coppie chiave/valore con tutte le opzioni dell’estensione. Queste opzioni possono essere passate all’estensione come segue:

    Quando si creano le proprie estensioni si consiglia di utilizzare il proprio spazio di nomi, giacchhé mette in chiaro da dove proviene l’estensione e se fa parte di una collezione più ampia. D’altra parte, lo spazio dei nomi ui è riservato per le estensioni ufficiali di jQuery UI.
    8.4: Passare opzioni al widget
    ⤽
    Copia codice
    
    $("<div></div>")
        .appendTo( "body" )
        .progressbar({ value: 20 });
    
    Quando si chiama a jQuery.widget si estende jQuery aggiungendo il metodo a jQuery.fn (nello stesso modo come quando si crea una estensione standard). Il nome della funzione che viene aggiunto è basato sul nome che si passa a jQuery.widget, senza lo spazio dei nomi (in questo caso il nome sarà jQuery.fn.progressbar).

    Come si mostra sotto, è possibile specificare valori predefiniti per ogni opzione. Questi valori dovrebbero essere basati sull’uso più comune dell’estensione.
    8.5: Impostare le opzioni di default per un widget

    ⤽
    Copia codice
    
    $.widget("nmk.progressbar", {
        // opzioni predefinite
        options: {
            value: 0
        },
        _create: function() {
            var progress = this.options.value + "%";
            this.element
                .addClass( "progressbar" )
                .text( progress );
        }
    });
    
    Aggiungere metodi a un Widget
    ⤽
    Ora è possibile inizializzare l’estensione, è necessario aggiungere le capacità di eseguire azioni attraverso metodi definiti nell’estensione. Per definire un metodo nell’estensione è necessario includere la funzione di retrochiamata nell’oggetto letterale da passare a jQuery.widget. I metodi possono anche essere definiti “privati” anteponendo un carattere di sottolineatura al nome della funzione.
    8.6: Creare metodi nel Widget
    ⤽
    Copia codice
    
    $.widget("nmk.progressbar", {
        options: {
            value: 0
        },
        _create: function() {
            var progress = this.options.value + "%";
            this.element
                .addClass("progressbar")
                .text(progress);
        },
        // crea un metodo pubblico
        value: function(value) {
            // non si passa alcun valore,
            // agisce quindi come metodo ottenitore (getter)
            if (value === undefined) {
                return this.options.value;
            // passando un valore, agisce quindi
            // come metodo impostatore (setter)
            } else {
                this.options.value = this._constrain(value);
                var progress = this.options.value + "%";
                this.element.text(progress);
            }
        },
        // crea un metodo privato
        _constrain: function(value) {
            if (value > 100) {
                value = 100;
            }
            if (value < 0) {
                value = 0;
            }
            return value;
        }
    });
    
    Per chiamare un metodo su un’istanza dell’estensione, è necessario passare il nome del metodo all’estensione. Se si chiama un metodo che accetta parametri questi devono essere passati subito dopo il nome del metodo.
    8.7: Chiamare i metodi in un'istanza dell'estensione
    ⤽
    Copia codice
    
    var bar = $("<div></div>")
        .appendTo("body")
        .progressbar({ value: 20 });
    // ottiene il valore corrente
    alert(bar.progressbar("value"));
    // aggiorna il valore
    bar.progressbar("value", 50);
    // ottiene di nuovo il valore
    alert(bar.progressbar("value"));
    
    Eseguire il metodo passando il nome del metodo allla stessa funzione jQuery che viene utilizzata per inizializzare l’estensione può sembrare strano, ma è fatto così per evitare “le contaminazioni” dello spazio di nomi di jQuery, mantenendo, allo stesso tempo, la possibilità di chiamare i metodi in catena o concatenati.
    Lavorare con le opzioni del Widget
    ⤽
    Uno dei metodi disponibili automaticamente per l’estensione è option. Questo metodo permette di ottenere e impostare opzioni dopo l’inizializzazione e funziona esattamente come i metodi attr e css di jQuery: passando unicamente un nome come argomento il metodo funziona come un getter, invece passando uno o più insiemi di coppie di nomi e valori il metodo funziona come setter. Se utilizzato come metodo getter, l’estensione restituirà il valore corrente dell’opzione corrispondente al nome passato come argomento. D’altra parte, se usato come metodo setter, il metodo _setOption dell’estensione sarà chiamato da ogni opzione che si desidera impostare.
    8.8: Risponde quando l'opzione è impostata
    ⤽
    Copia codice
    
    $.widget("nmk.progressbar", {
        options: {
            value: 0
        },
        _create: function() {
            this.element.addClass("progressbar");
            this._update();
        },
        _setOption: function(key, value) {
            this.options[key] = value;
            this._update();
        },
        _update: function() {
            var progress = this.options.value + "%";
            this.element.text(progress);
        }
    });
    
    Aggiungere funzioni di callback
    ⤽
    Uno dei modi più semplici per estendere un’estensione è quello di aggiungere funzioni di callback, in modo che l’utente possa reagire quando lo stato dell’estensione cambia. Di seguito viene riportato come aggiungere una funzione di callback all’estensione creata per indicare quando la barra di progresso raggiunge il 100%. Il metodo _trigger riceve tre parametri: il nome della funzione di callback, l’oggetto evento nativo che inizializza la funzione di callback e una serie di informazioni relative all’evento. Il nome della funzione di retrochiamata (callback in inglese) è l’unico parametro richiesto, ma altre possono essere molto utile se l’utente vuole implementare funzionalità personalizzate.
    8.9: Fornire funzioni di (callback) retrochiamata
    ⤽
    Copia codice
    
    $.widget("nmk.progressbar", {
        options: {
            value: 0
        },
        _create: function() {
            this.element.addClass("progressbar");
            this._update();
        },
        _setOption: function(key, value) {
            this.options[key] = value;
            this._update();
        },
        _update: function() {
            var progress = this.options.value + "%";
            this.element.text(progress);
            if (this.options.value == 100) {
                this._trigger("complete", null, { value: 100 });
            }
        }
    });
    
    Le funzioni di callback sono essenzialmente solo opzioni aggiuntive e possono essere impostate come qualsiasi altra opzione. Ogni volta che una funzione di callback viene eseguita, allo stesso tempo si attiva un evento corrispondente. Il tipo di evento si determina concatenando il nome dell’estensione e il nome della funzione di callback. Questa funzione ed evento ricevono gli stessi parametri: un oggetto evento e una serie di informazioni relative all’evento.

    Se l’estensione avrà qualche funzionalità che potrebbero essere annullate dall’utente, il modo migliore è quello di creare funzioni di callback annullabile. L’utente può annullare una funzione di callback o il suo evento associato nello stesso modo che viene annullato qualunque evento nativo: chiamando a event.preventDefault() o usando return false.
    8.10: Vincolare a eventi del widget

    ⤽
    Copia codice
    
    var bar = $("<div></div>")
        .appendTo("body")
        .progressbar({
            complete: function(event, data) {
                alert( "Funzione di callback" );
            }
        })
        .bind("progressbarcomplete", function(event, data) {
            alert("Eventi bolla e molti gestori di supporto per una flessibilità estrema.");
            alert("Il valore della barra di avanzamento è " + data.value);
        });
    bar.progressbar("option", "value", 100);
    
    In profondità: Widget Factory
    ⤽
    Quando si chiama a jQuery.widget, questa crea una funzione costruttrice per l’estensione e imposta l’oggetto letterale che viene passato come il prototipo per tutte le istanze dell’l’estensione. Tutte le caratteristiche che automaticamente si aggiungono all’estensione provvengono dal prototipo base del widget, il quale è definito come jQuery.Widget.prototype. Quando si crea un’istanza dell’estensione, questa viene salvata nell’elemento originale del DOM utilizzando jQuery.data, con il nome dell’estensione come parola chiave.

    Perché l’istanza dell’estensione è direttamente legata all’elemento DOM, è possibile accedere all’istanza dell’estensione direttamente. Questo permette di chiamare i metodi direttamente nell’istanza dell’estensione invece di passare il nome del metodo come una stringa, dando la possibilità di accedere alle proprietà dell’estensione.

    Copia codice
    
    var bar = $("<div></div>")
        .appendTo("body")
        .progressbar()
        .data("progressbar" );
    // chiamare un metodo direttamente
    // nell'istanza dell'estensione
    bar.option("value", 50);
    // accedere alle proprietà
    // nell'istanza dell'estensione
    alert(bar.options.value);
    
    Uno dei maggiori vantaggi di avere un costruttore e un prototipo per l’estensione è la facilità di estendere l’estensione. Il fatto di aggiungere o modificare metodi nel prototipo dell’estensione permette di modificarli anche in tutte le istanze dell’estensione. Per esempio, se vogliamo aggiungere un metodo all’estensione della barra di avanzamento per permettere di resettare il progresso a 0%, è possibile farlo aggiungendo questo metodo al prototipo e sarà automaticamente disponibile per essere chiamato da qualsiasi istanza dell’estensione.
    Copia codice
    
    $.nmk.progressbar.prototype.reset = function() {
        this._setOption("value", 0);
    };
    
    Pulizia
    ⤽
    In alcuni casi, ha senso consentire agli utenti di applicare e disapplicare l’estensione. Questo può essere fatto attraverso il metodo destroy. Con questo metodo, è possibile annullare tutto quello che si è fatto con l’estensione. Questo metodo è anche chiamato automaticamente se l’elemento vincolato all’estensione viene rimosso dal DOM (e così è anche possibile usarlo per la raccolta di spazzatura o in inglese “garbage collection”). Il metodo destroy predefinito rimuove il collegamento tra l’elemento DOM e l’istanza dell’estensione.
    8.11: Aggiungere un metodo destroy al widget
    ⤽
    Copia codice
    
    $.widget( "nmk.progressbar", {
        options: {
            value: 0
        },
        _create: function() {
            this.element.addClass("progressbar");
            this._update();
        },
        _setOption: function(key, value) {
            this.options[key] = value;
            this._update();
        },
        _update: function() {
            var progress = this.options.value + "%";
            this.element.text(progress);
            if (this.options.value == 100 ) {
                this._trigger("complete", null, { value: 100 });
            }
        },
        destroy: function() {
            this.element
                .removeClass("progressbar")
                .text("");
            // chiama alla funzione base destroy
            $.Widget.prototype.destroy.call(this);
        }
    });
    
    Conclusione
    ⤽
    L’utilizzo di Widget factory è solo un modo per creare estensioni con la manutenzione dello stato. Ci sono modelli diversi che possono essere usati e ognuno di loro ha i suoi vantaggi e svantaggi. Widget factory risolve molti problemi comuni, migliorando significativamente la produttività e il riutilizzo del codice.
    Esercizi
    ⤽
    Creare una tabella ordinabile
    ⤽
    Per questo esercizio, il compito è quello di individuare, scaricare e implementare un’estensione che permetta di ordinare la tabella esistente nella pagina index.html. Quando è pronto, tutte le colonne della tabella dovrebbero essere in grado di essere ordinabili.
    Scrivere un'estensione per cambiare il colore di sfondo nelle tabelle
    ⤽
    Aprire il file /exercises/index.html nel browser web. Eseguire l’esercizio utilizzando il file /exercises/js/stripe.js. Il compito è quello di scrivere un’estensione chiamata “stripe”, il quale potrà essere chiamata da qualsiasi elemento table e dovrà cambiare il colore di sfondo delle righe dispari nel corpo della tabella. Il colore potrà essere specificato come parametro dell’estensione.
    Copia codice
    
    $('#myTable').stripe('#cccccc');
    
    Non dimenticare di restituire la tabella in modo che altri metodi possano essere concatenati dopo la chiamata all’estensione.
    [nextpage title=”Best practice per migliorare le prestazioni”] Questo capitolo tratta molte migliori pratiche JavaScript e jQuery, senza un particolare ordine.
    Molte di queste pratiche si basano sulla presentazione jQuery Anti-Patterns for Performance (in inglese) di Paul irlandese.
    Salva la lunghezza del loops
    ⤽
    In un ciclo, è necessario accedere alla lunghezza di un array ogni volta che viene valutata la condizione; tale valore può essere memorizzato in anticipo in una variabile.
    Copia codice
    
    var myLength = myArray.length;
    for (var i = 0; i < myLength; i++) {
        // fare delle cose
    }
    
    Aggiungere nuovi contenuti fuori da un ciclo
    ⤽
    Se si sta inserendo molti elementi nel DOM, fatelo tutti in una volta, non uno per volta.
    Copia codice
    
    // male
    $.each(myArray, function(i, item) {
       var newListItem = '<li>' + item + '</li>';
       $('#ballers').append(newListItem);
    });
    // meglio: fare questo
    var frag = document.createDocumentFragment();
    $.each(myArray, function(i, item) {
        var newListItem = '<li>' + item + '</li>';
        frag.appendChild(newListItem);
    });
    $('#ballers')[0].appendChild(frag);
    // o questo
    var myHtml = '';
    $.each(myArray, function(i, item) {
        html += '<li>' + item + '</li>';
    });
    $('#ballers').html(myHtml);
    
    Non Ripetersi
    ⤽
    Nessuna ricorrenza; fare le cose una volta e solo una, altrimenti è sbagliato.
    Copia codice
    
    // MALE
    if ($eventfade.data('currently') != 'showing') {
        $eventfade.stop();
    }
    if ($eventhover.data('currently') != 'showing') {
        $eventhover.stop();
    }
    if ($spans.data('currently') != 'showing') {
        $spans.stop();
    }
    // BENE
    var $elems = [$eventfade, $eventhover, $spans];
    $.each($elems, function(i,elem) {
        if (elem.data('currently') != 'showing') {
            elem.stop();
        }
    });
    
    Attenzione alle funzioni anonime
    ⤽
    Non è consigliabile utilizzare abbondantemente le funzioni anonime. Queste sono difficili da eseguire in debug, per la manutenzione, il test e suo riutilizzo. Al suo posto, utilizzare un valore letterale per organizzare e nominare i suoi controllori e le funzioni di retrochiamata (callback).
    Copia codice
    
    // MALE
    $(document).ready(function() {
        $('#magic').click(function(e) {
            $('#yayeffects').slideUp(function() {
                // ...
            });
        });
        $('#happiness').load(url + ' #unicorns', function() {
            // ...
        });
    });
    // MEGLIO
    var PI = {
        onReady : function() {
            $('#magic').click(PI.candyMtn);
            $('#happiness').load(PI.url + ' #unicorns', PI.unicornCb);
        },
        candyMtn : function(e) {
            $('#yayeffects').slideUp(PI.slideCb);
        },
        slideCb : function() { ... },
        unicornCb : function() { ... }
    };
    $(document).ready(PI.onReady);
    
    Ottimizzazione dei selettori
    ⤽
    L’ottimizzazione dei selettori è meno importante di una volta, grazie all’implementazione in alcuni browser web document.querySelectorAll(), passando il peso di jQuery verso browser web. Tuttavia, ci sono alcuni consigli da tenere a mente.
    Selettori basati sugli ID
    ⤽
    È sempre meglio iniziare le selezioni con un ID.
    Copia codice
    
    // veloce
    $('#container div.robotarm');
    // super-veloce
    $('#container').find('div.robotarm');
    
    L’esempio che utilizza $.fn.find è più veloce perché la prima selezione utilizza il motore di selezione interno Sizzle -. Mentre la selezione realizzata unicamente per ID utilizza document.getElementById(), che è estremamente veloce grazie alla è una funzione nativa del browser web.
    Specificità
    ⤽
    Cercate di essere specifico per il lato destro della selezione e meno specifici per il sinistro.
    Copia codice
    
    // non ottimizzato
    $('div.data .gonzalez');
    // ottimizzato
    $('.data td.gonzalez');
    
    Utilizzare il più possibile tag.classe del lato destro della selezione, e solo tag o .classe a sinistra.

    Evitare specificità eccessiva

    Copia codice
    
    $('.data table.attendees td.gonzalez');
    // molto meglio: eliminare il mezzo, se possibile,
    $('.data td.gonzalez');
    
    La seconda selezione ha prestazioni migliori perché attraversa meno strati per individuare l’elemento.
    Evitare il selettore universale
    ⤽
    Selezioni dove si specifica implicita o esplicitamente una selezione universale che può essere molto lento.
    Copia codice
    
    $('.buttons > *');  // molto lento
    $('.buttons').children();  // molto meglio
    $('.gender :radio');  // selezione universale implicita
    $('.gender *:radio'); // stesa cosa, ma in modo esplicito
    $('.gender input:radio'); // molto meglio
    
    Utilizzare la delegazione di Eventi
    ⤽
    La delega di eventi permette vincolare un gestore eventi a un elemento contenitore (per esempio, una lista non ordinata) in luogo di molteplici elementi contenuti (per esempio, gli elementi in una lista). jQuery rende rende questo lavoro facile attraverso $.fn.live e $.fn.delegate. Se possibile, si raccomanda utilizzare $.fn.delegate anziché $.fn.live, giacché elimina la necessità di una selezione e il suo contesto esplicito riduce il carico di circa il 80%.

    Inoltre, la delegazione di eventi permette di aggiungere nuovi elementi contenitori alla pagina, senza dover vincolare i loro gestori di eventi.

    Copia codice
    
    // sbagliato (se ci sono molti elementi nella lista)
    $('li.trigger').click(handlerFn);
    // meglio: delegazione di eventi con $ fn.live.
    $('li.trigger').live('click', handlerFn);
    // molto meglio:. delegazione di evento con $ fn.delegate
    // permette specificare un contesto in modo facile
    $('#myList').delegate('li.trigger', 'click', handlerFn);
    
    Separare elementi per lavorare con loro
    ⤽
    Se possibile, evitare la manipolazione del DOM. Per contribuire a questo scopo, dalla versione 1.4 jQuery introduce $.fn.detach il quale permette lavorare con gli elementi del DOM in forma separata per poi inserirli.
    Copia codice
    
    var $table = $('#myTable');
    var $parent = $table.parent();
    $table.detach();
    // ... si aggiungono molte celle alla tabella
    $parent.append($table);
    
    Utilizzare stili a cascata per modificare il Css tra vari elementi
    ⤽
    Se si modifica il CSS in più di 20 elementi con $.fn.css, considerate le modifiche agli stili con l’aggiunta di un tag style. Ciò consentirà di aumentare le prestazioni del 60%.
    Copia codice
    
    // corretto fino a 20 elementi, lento dopo i 20 elementi
    $('a.swedberg').css('color', '#asd123');
    $('<style type="text/css">a.swedberg { color : #asd123 }</style>')
        .appendTo('head');
    
    Utilizzare $.data anziché $.fn.data
    ⤽
    Utilizzare $.data in un elemento DOM invece di $.fn.data in una selezione può essere fino a 10 volte più veloce. Prima di farlo, assicuratevi di capire la differenza tra un elemento DOM e una selezione jQuery.
    Copia codice
    
    // regolare
    $(elem).data(key,value);
    // 10 volte più veloce
    $.data(elem,key,value);
    
    Non agire su elementi inesistenti
    ⤽
    jQuery non ci dirà se si cerca di eseguire un codice su una selezione vuota – questo verrà eseguito come se nulla fosse. Dipende da noi vedere se la selezione contiene elementi.
    Copia codice
    
    // SBAGLIATO: il codice esegue tre funzioni
    // senza verificare se ci sono
    // nella selezione
    $('#nosuchthing').slideUp();
    // MEGLIO
    var $mySelection = $('#nosuchthing');
    if ($mySelection.length) { $mySelection.slideUp(); }
    // MOLTO MEGLIO: aggiunge una estensione doOnce
    jQuery.fn.doOnce = function(func){
        this.length && func.apply(this);
        return this;
    }
    $('li.cartitems').doOnce(function(){
        // fare qualcosa
    });
    
    Questo consiglio è particolarmente adatto per i widget jQuery UI, i quali hanno un carico pesante, anche quando la selezione non contiene elementi.
    Definizione di variabili
    ⤽
    Le variabili possono essere definite in una unica dichiarazione, invece di più volte.
    Copia codice
    
    // antico
    var test = 1;
    var test2 = function() { ... };
    var test3 = test2(test);
    // migliore modo
    var test = 1,
        test2 = function() { ... },
        test3 = test2(test);
    
    Nelle funzioni di autoeseguibili, le definizioni di variabili possono essere passate tutte insieme.
    Copia codice
    
    (function(foo, bar) { ... })(1, 2);
    
    Condizionali
    ⤽
    Copia codice
    
    // antico
    if (type == 'foo' || type == 'bar') { ... }
    // migliore
    if (/^(foo|bar)$/.test(type)) { ... }
    // ricerca in oggetto letterale
    if (({ foo : 1, bar : 1 })[type]) { ... }
    
    Non trattare jQuery come se fosse una scatola nera
    ⤽
    Utilizzare il codice sorgente della libreria come se fosse la sua documentazione – salva il link http://bit.ly/jqsource come marcatore per usarlo come riferimento.
    [nextpage title=”Organizzazione del codice”] Introduzione
    ⤽
    Quando si intraprende il compito di realizzare applicazioni complesse sul lato client, è necessario considerare come organizzare il codice. Questo capitolo è dedicato ad analizzare alcuni modelli di organizzazione del codice da utilizzare in un’applicazione realizzata con jQuery ed esplorare il sistema di gestione di dipendenze di RequireJS.
    Concetti chiave
    ⤽
    Prima di iniziare con i modelli organizzativi di codice, è importante capire alcuni concetti chiave.

    • Il codice deve essere suddiviso in unità funzionali – moduli, servizi, ecc. E devono evitare la tentazione di avere tutto in un unico blocco $(document).ready(). Questo concetto è noto come incapsulamento.
    • Non ripetere il codice. Identificare pezzi simili e utilizzare tecniche di eredità.
    • Sebbene la natura di jQuery, non tutte le applicazioni JavaScript si trovano nel DOM e non tutte le parti di funzionalità hanno la necessità di avere un rappresentanzio nel DOM.
    • Le unità di funzionalità devono avere un giunto flessibile (in inglese loosely coupled) – una unità di funzionalità dovrebbe essere in grado di esistere da sé e la comunicazione con altre unità dovrebbe avvenire attraverso un sistema di messaggi come eventi personalizzati o pub/sub. E per quanto possibile, tenere lontana la comunicazione diretta le unità funzionali.

    Il concetto di giunto (o articolazione) flessibile può essere particolarmente problematico per gli sviluppatori che fanno la loro prima incursione in applicazioni complesse, quindi se siete di partenza, cercate di essere consapevoli di questo concetto.

    Incapsulamento
    ⤽
    Il primo passo per l’organizzazione del codice è di separare l’applicazione in diversi pezzi; anche se a volte, questo sforzo è sufficiente.
    L'Oggetto Letterale
    ⤽
    Un oggetto letterale è forse il modo più semplice per incapsulare il codice correlato. Questo non fornisce alcuna privacità per proprietà o metodi, ma è utile per eliminare le funzioni anonime, centralizzare le opzioni di configurazione, e facilitare la via per il riutilizzo e il rifattorizzazione.
    10.1: Un oggetto letterale
    ⤽
    Copia codice
    
    var myFeature = {
    myProperty : 'ciao',
    myMethod : function() {
        console.log(myFeature.myProperty);
    },
    init : function(settings) {
        myFeature.settings = settings;
    },
    readSettings : function() {
        console.log(myFeature.settings);
    }
    };
    myFeature.myProperty; // 'ciao'
    myFeature.myMethod(); // registra 'ciao'
    myFeature.init({ foo : 'bar' });
    myFeature.readSettings(); // registra { foo : 'bar' }
    
    L’oggetto ha una proprietà e vari metodi, i quali sono pubblici, in modo che ogni parte dell’applicazione li può vedere.

    Come è possibile applicare questo schema nel codice jQuery? Per esempio, nel codice seguente scritto nello stile tradizionale di jQuery:

    Copia codice
    
    // Facendo clic su un item della lista
    // si carica un certo contenuto.
    // Utilizzando l'ID dell'item e a sua
    // volta nasconde gli altri item fratelli.
    $(document).ready(function() {
    $('#myFeature li')
    .append('<div/>')
    .click(function() {
      var $this = $(this);
      var $div = $this.find('div');
      $div.load('foo.php?item=' +
        $this.attr('id'),
        function() {
          $div.show();
          $this.siblings()
            .find('div').hide();
        }
      );
    });
    });
    
    Se l’esempio illustrato rappresenta il 100% della richiesta, si consiglia di lasciare così com’è. Tuttavia, se il pezzo è solo una parte di una applicazione più grande, sarebbe bene separare questa funzionalità dalle altre non correlate. Per esempio è conveniente spostare l’URL a cui viene fatta la richiesta al di fuori del codice e passarla all’area di configurazione. Anche spezzare la catena di metodi per rendere dopo più facile la sua modifica o manutensione.
    10.2: Utilizzare un oggetto letterale per una funzionalità jQuery
    ⤽
    Copia codice
    
    var myFeature = {
    init : function(settings) {
        myFeature.config = {
            $items : $('#myFeature li'),
            $container : $('<div class="container"></div>'),
            urlBase : '/foo.php?item='
        };
        // permete di sovrascrivere
        // la configurazione predefinita
        $.extend(myFeature.config, settings);
        myFeature.setup();
    },
    setup : function() {
        myFeature.config.$items
            .each(myFeature.createContainer)
            .click(myFeature.showItem);
    },
    createContainer : function() {
        var $i = $(this),
            $c = myFeature.config.$container.clone()
                     .appendTo($i);
        $i.data('container', $c);
    },
    buildUrl : function() {
        return myFeature.config.urlBase +
               myFeature.$currentItem.attr('id');
    },
    showItem : function() {
        var myFeature.$currentItem = $(this);
        myFeature.getContent(myFeature.showContent);
    },
    getContent : function(callback) {
        var url = myFeature.buildUrl();
        myFeature.$currentItem
            .data('container').load(url, callback);
    },
    showContent : function() {
        myFeature.$currentItem
            .data('container').show();
        myFeature.hideContent();
    },
    hideContent : function() {
        myFeature.$currentItem.siblings()
            .each(function() {
                $(this).data('container').hide();
            });
    }
    };
    $(document).ready(myFeature.init);
    
    La prima caratteristica da notare è che il codice è più lungo da quello originale – come affermato in precedenza, se questo è il campo dell’applicazione, utilizzare un oggetto letterale sarebbe probabilmente una esagerazione.

    I vantaggi sono:

    • Separazione di ogni funzionalità in piccoli metodi. In futuro, se si desidera cambiare la modo di visualizzare il contenuto, ci sarà chiaro dove farlo. Nel codice originale, questo passaggio è molto più difficile da individuare.
    • Si rimuovono gli usi di funzioni anonime.
    • Le opzioni di configurazione ssi sono spostate in una posizione centrale.
    • Si eliminano le limitazioni che hanno catene di metodi, rendendo il codice più facile da rifattorare, mescolare e riordinare.

    Grazie alle sue caratteristiche, l’uso di oggetti letterali consente un netto miglioramento per lunghi tratti di codice inseriti in un blocco $(document).ready(). Tuttavia, no sono più avanzati che avere diverse dichiarazioni di funzioni all’interno di un blocco $(document).ready().

    Il Modello Modulare
    ⤽
    Il modello modulare supera alcune delle limitazioni dell’oggetto letterale, offrendo privacità a variabili e funzioni, esponendo a sua volta un API pubblica se lo si desidera.
    10.3: Il modello modulare
    ⤽
    Copia codice
    
    var feature =(function() {
    // variabili e funzioni private
    var privateThing = 'segreto',
        publicThing = 'non segreto',
        changePrivateThing = function() {
            privateThing = 'super segreto';
        },
        sayPrivateThing = function() {
            console.log(privateThing);
            changePrivateThing();
        };
    // API pubblica
    return {
        publicThing : publicThing,
        sayPrivateThing : sayPrivateThing
    }
    })();
    feature.publicThing; // registra 'non segreto'
    feature.sayPrivateThing();
    // registra 'segreto' e cambia il valore
    // di privateThing a 'super segreto'
    
    Nell’esempio, si autoesegue un funzione anonima che restituisce un oggetto. All’interno della funzione, si definiscono alcune variabili. Visto che sono definite all’interno della funzione, dall’esterno non hanno accesso a meno che non si mettano dentro l’oggetto che viene restituito. Questo significa che nessun codice al di fuori della funzione ha accesso alla variabile privateThing o alla funzione sayPrivateThing. Tuttavia, sayPrivateThing ha accesso a privateThing e changePrivateThing perche sono definiti nello stesso ambito.

    Il modello è potente perché permette di avere variabili e funzioni private, esponendo una API limitata che consente la retituzione di proprietà e metodi di un oggetto.

    Di seguito è riportato una revisione dell’esempio visto prima, con le stesse caratteristiche, ma esponendo un unico metodo pubblico del modulo, showItemByIndex().
    10.4: Utilizzare il modello modulare per una funzionalità jQuery

    ⤽
    Copia codice
    
    $(document).ready(function() {
    var feature = (function() {
        var $items = $('#myFeature li'),
            $container = $('<div class="container"></div>'),
            $currentItem,
            urlBase = '/foo.php?item=',
            createContainer = function() {
                var $i = $(this),
                    $c = $container.clone().appendTo($i);
                $i.data('container', $c);
            },
            buildUrl = function() {
                return urlBase + $currentItem.attr('id');
            },
            showItem = function() {
                var $currentItem = $(this);
                getContent(showContent);
            },
            showItemByIndex = function(idx) {
                $.proxy(showItem, $items.get(idx));
            },
            getContent = function(callback) {
                $currentItem.data('container').load(buildUrl(), callback);
            },
            showContent = function() {
                $currentItem.data('container').show();
                hideContent();
            },
            hideContent = function() {
                $currentItem.siblings()
                    .each(function() {
                        $(this).data('container').hide();
                });
            };
        $items
            .each(createContainer)
            .click(showItem);
        return { showItemByIndex : showItemByIndex };
    })();
    feature.showItemByIndex(0);
    });
    
    Gestione delle dipendenze
    ⤽
    Questa sezione si basa sulla eccellente documentazione di RequireJS http://requirejs.org/docs/jquery.html ed è utilizzato con il permesso di James Burke, autore di RequireJS.

    Quando un progetto raggiunge una certa dimensione, cominicia a diventare difficile la gestione dei moduli in un’applicazione, giacché è necessario sapere ordinarli in modo corretto, e cominciare a combinarli in un unico file per ottenere il minor numero di richieste. È anche possibile che si voglia caricare codice “al volo” dopo il caricamento della pagina.

    RequireJS è uno strumento per la gestione delle dipendenze creato da James Burke, che aiuta a gestire i moduli, caricarli nel giusto ordine e combinarli con facilità, senza dover apportare alcuna modifica. A sua volta, fornisce un modo semplice per caricare il codice una volta caricata la pagina, permettendo di minimizzare il tempo di download.

    RequireJS possiede un sistema modulare, ma non c’è bisogno di seguirlo per ottenere i sui benefici. Il formato modulare di RequireJS permette la scrittura del codice incapsulato, incorporazione dell’internazionalizzazione (i18n) ai pacchetti (per consentirne l’uso in diverse lingue) e anche l’uso dei servizi JSONP come dipendenze.
    Ottenere RequireJS

    ⤽
    Il modo più semplice per usare il pacchetto RequireJS con jQuery è quello di scaricare el paquete de jQuery con RequireJS già incorporato. Questo pacchetto esclude porzioni di codice che duplicano funzioni di jQuery.
    È anche utile scaricare un esempio di progetto jQuery che utilizza RequireJS.
    Utilizzare RequireJS con jQuery
    ⤽
    Utilizzare RequireJS è semplice, basta inserire nella pagina la versione jQuery che ha costruito RequireJS includendo e quindi richiedere i files dell’applicazione. Di seguito, l’esempio presuppone che sia jQuery come gli altri files siano all’interno della cartella scripts/.
    10.5: Usare RequireJS: un semplice esempio
    ⤽
    Copia codice
    
    <!DOCTYPE html>
    <html>
    <head>
        <title>jQuery+RequireJS pagina di esempio</title>
        <script src="scripts/require-jquery.js"></script>
        <script>require(["app"]);</script>
    </head>
    <body>
        <h1>jQuery+RequireJS pagina di esempio</h1>
    </body>
    </html>
    
    La chiamata a require([“app”]) comunica a RequireJS che carichi il file scripts/app.js. RequireJS caricherà qualsiasi dipendenza passata a require() senza l’estensione .js dalla stessa cartella in cui si trova il file require-jquery.js, ma è anche possibile specificare il percorso così come segue:
    Copia codice
    
    <script>require(["scripts/app.js"]);</script>
    
    Il file app.js è un’altra chiamata al file require.js per caricare tutti i file necessari per l’applicazione. Nel seguente esempio, app.js si richiedono due estensioni jquery.alpha.js e jquery.beta.js (non sono estensioni reali, solo esempi). Queste estensioni sono nella stessa cartella del file require-jquery.js:
    10.6: Un semplice file JavaScript con dipendenze
    ⤽
    Copia codice
    
    require(["jquery.alpha", "jquery.beta"], function() {
    // le estensioni  jquery.alpha.js y jquery.beta.js
    // sono state caricate.
    $(function() {
        $('body').alpha().beta();
    });
    });
    
    Creare moduli riutilizzabili con RequireJS
    ⤽
    RequireJS rende facile definire moduli riutilizzabili attraverso require.def(). Un modulo RequireJS può avere dipendenze che possono essere utilizzati per definire un modulo così come per restituire un valore – un oggetto, una funzione o qualcos’altro – che può essere utilizzato anche su altri moduli.

    Se il modulo non ha dipendenze, solo si deve specificare il il nome come primo argomento di require.def(). Il secondo argomento è un oggetto letterale che definisce le proprietà del modulo. Per esempio:
    10.7: Definizione di un modulo RequireJS che non ha dipendenze

    ⤽
    Copia codice
    
    require.def("my/simpleshirt",
    {
        color: "black",
        size: "unisize"
    }
    );
    
    L’esempio deve essere salvato nel file my/simpleshirt.js.

    Se il modulo ha dipendenze, si può specificare nel secondo argomento di require.def() attraverso un array e poi passare una funzione come terzo argomento. Questa funzione sarà chiamata per definire il modulo una volta caricate tutte le dipendenze. Questa funzione riceve i valori restituiti dalle dipendenze come argomento (nello stesso ordine in cui sono dichiarate nell’array), allora la stessa deve restituire un oggetto che definisca il modulo.
    10.8: Definizione di un modulo RequireJS con dipendenze

    ⤽
    Copia codice
    
    require.def("my/shirt",
    ["my/cart", "my/inventory"],
    function(cart, inventory) {
        // restituisce un oggetto che definisce
        // il modulo "my/shirt".
        return {
            color: "blue",
            size: "large"
            addToCart: function() {
                inventory.decrement(this);
                cart.add(this);
            }
        }
    }
    );
    
    In questo esempio, il modulo my/shirt viene creato. Questo dipende da my/cart e my/inventory. Sul disco, i files sono strutturati come segue:
    Copia codice
    
    my/cart.js
    my/inventory.js
    my/shirt.js
    
    La funzione che definisce my/shirt non viene chiamata fino a che my/cart e my/inventory siano stati caricati, e questa funzione riceve come argomenti i moduli cart e inventory. L’ordine degli argomenti della funzione deve corrispondere all’ordine in cui le dipendenze si richiedono nell’array. L’oggetto restituito definisce il modulo my/shirt. Definendo i moduli in questo modo, my/shirt non esiste come un oggetto globale, giacché più moduli possono esistere nella pagina allo stesso tempo.

    I moduli non devono per forza restituire un oggetto, qualsiasi tipo di valore è permesso.
    10.9: Definizione di un modulo RequireJS che restituisce una funzione

    ⤽
    Copia codice
    
    require.def("my/title",
    ["my/dependency1", "my/dependency2"],
    function(dep1, dep2) {
        // restituisce una funzione per definire "my/title".
        // Questo restituisce o imposta
        // il titolo della finestra
        return function(title) {
            return title ? (window.title = title) : window.title;
        }
    }
    );
    
    Un solo modulo dovrebbe essere richiesto per il file JavaScript.
    Ottimizzare il codice con gli strumenti di RequireJS
    ⤽
    Una volta incorporato RequireJS per la gestione delle dipendenze, ottimizzazione del codice è semplice. Scarica il pacchetto RequireJS e salvarlo, preferibilmente al di fuori dell’area di sviluppo web. Ai fini del presente esempio, il pacchetto RequireJS si trova in una cartella parallela alla cartella webapp (che contiene la pagina HTML e tutti i file JavaScript dell’applicazione). La struttura della cartella è la seguente:
    Copia codice
    
    requirejs/ (utilizzayo per eseguire gli strumenti)
    webapp/app.html
    webapp/scripts/app.js
    webapp/scripts/require-jquery.js
    webapp/scripts/jquery.alpha.js
    webapp/scripts/jquery.beta.js
    
    Poi, nella cartella degli script che ha require-jquery.js e app.js creare un file chiamato app.build.js o con il seguente contenuto:
    10.10: File di configurazione per gli strumenti di ottimizzazione di RequireJS
    ⤽
    Copia codice
    
    {
    appDir: "../",
    baseUrl: "scripts/",
    dir: "../../webapp-build",
    // Commentare la riga seguente se volete
    // minimizzare il codice dal compilatore
    // in modalità "semplice"
    optimize: "none",
    modules: [
        {
            name: "app"
        }
    ]
    }
    
    Per utilizzare lo strumento, è necessario installare Java 6. Closure Compiler viene utilizzato per minimizzare il codice (nel caso optimize: “none” non sia commentato).

    Per avviare l’elaborazione dei files, aprire una finestra di comando, andare alla cartella webapp/scripts ed eseguire:

    Copia codice
    
    # per sistemi non-Windows
    ../../requirejs/build/build.sh app.build.js
    # per sistemi Windows
    ..\..\requirejs\build\build.bat app.build.js
    
    Una volta eseguito, il file app.js nella cartella webapp-build conterrà tutto il codice di app.js più quello di jquery.alpha.js e jquery.beta.js. Se viene aperto il file app.html (anche nella cartella webapp-build) si noterà che nessuna richiesta si realizza per caricare jquery.alpha.js e jquery.beta.js.
    Esercizi
    ⤽
    Creare un modulo Portlet
    ⤽
    Aprire il file /exercises/portlets.html nel browser web. Eseguire l’esercizio utilizzando il file /exercises/js/portlets.js. L’esercizio è quello di creare una funzione che crea portlet che utilizza il modello modulare, in modo che il codice che segue funzioni:
    Copia codice
    
    var myPortlet = Portlet({
    title : 'Curry',
    source : 'data/html/curry.html',
    initialState : 'open' // or 'closed'
    });
    myPortlet.$element.appendTo('body');
    
    Ogni portlet deve essere un div con un titolo, uno spazio per il contenuto, un pulsante per aprire/chiudere il portlet, un pulsante per rimuoverlo e un altro per aggiornarlo. Il portlet restituito dalla funzione deve avere la seguente API pubblicha:
    Copia codice
    
    myPortlet.open();    // forza per aprire
    myPortlet.close();   // forza per chiudere
    myPortlet.toggle();  // alterna gli stati
                         // tra aperto e chiuso
    myPortlet.refresh(); // aggiorna il contenuto
    myPortlet.destroy(); // rimuove il porlet dalla pagina
    myPortlet.setSource('data/html/onions.html');
                         // cambia il codice
    
    [nextpage title=”Eventi personalizzati”] Introduzione agli Eventi personalizzati
    ⤽
    Ormai yutti conoscono gli elementi di base – click, mouseover, focus, blur, submit, etc. – derivanti dall’interazione dell’utente con il browser web.

    Gli eventi personalizzati consentono di farsi un’idea del mondo della programmazione orientata a oggetti (in inglese event-driven programming). In questo capitolo useremo il sistema di eventi personalizzati di jQuery per creare una semplice applicazione di ricerca Twitter.

    In un primo momento può essere difficile da capire il requisito di utilizzare eventi personalizzati, visto che gli eventi convenzionali permettono di soddisfare tutte le esigenze. Tuttavia, gli eventi personalizzati offrono un modo nuovo di pensare la programmazione in JavaScript. Invece di concentrarsi sull’elemento che esegue un’azione, gli eventi personalizzati pongono l’attenzione sull’elemento in cui si verifica l’azione. Questo concetto offre diversi vantaggi:

    • Il comportamento dell’elemento obiettivo può essere eseguito da diversi elementi utilizzando lo stesso codice.
    • I comportamenti possono essere eseguiti in più o simili elementi obiettivi alla volta.
    • I comportamenti sono associati più chiaramente con l’elemento di obiettivo, rendendo il codice più facile da leggere e manutenere.

    Un esempio è il modo migliore per spiegare la questione. Supponiamo di avere una lampada a incandescenza in una stanza di una casa. La lampada è attualmente accessa. La stessa è controllata da due interruttori a tre posizioni e un clapper (switch attivato per applausi):

    Copia codice
    
    <div class="room" id="kitchen">
        <div class="lightbulb on"></div>
        <div class="switch"></div>
        <div class="switch"></div>
        <div class="clapper"></div>
    </div>
    
    Eseguendo il clapper o qualcuno degli interruttori, lo stato della lampada cambia. Agli interruttori o al clapper non si curano se la lampada è accesa o spenta, vogliono solo cambiare il loro stato.

    Senza l’utilizzo di eventi personalizzati, è possibile scrivere la routine come segue:

    Copia codice
    
    $('.switch, .clapper').click(function() {
        var $light = $(this).parent().find('.lightbulb');
        if ($light.hasClass('on')) {
            $light.removeClass('on').addClass('off');
        } else {
            $light.removeClass('off').addClass('on');
        }
    });
    
    D’altra parte, con gli eventi personalizzati, il codice appare così:
    Copia codice
    
    $('.lightbulb').bind('changeState', function(e) {
        var $light = $(this);
        if ($light.hasClass('on')) {
            $light.removeClass('on').addClass('off');
        } else {
            $light.removeClass('off').addClass('on');
        }
    });
    $('.switch, .clapper').click(function() {
        $(this).parent().find('.lightbulb').trigger('changeState');
    });
    
    Qualcosa di importante è successo: il comportamento della lampada è stata cambiata, prima erano sugli interruttori e nel clapper, ora si trova nella stessa lampada.

    E ‘anche possibile fare un esempio po’ più interessante. Supponiamo di aggiungere un’altra stanza nella casa, insieme ad uno switch generale, come illustrato di seguito:

    Copia codice
    
    <div class="room" id="kitchen">
        <div class="lightbulb on"></div>
        <div class="switch"></div>
        <div class="switch"></div>
        <div class="clapper"></div>
    </div>
    <div class="room" id="bedroom">
        <div class="lightbulb on"></div>
        <div class="switch"></div>
        <div class="switch"></div>
        <div class="clapper"></div>
    </div>
    <div id="master_switch"></div>
    
    Se c’è una lampada accesa in casa, è possibile spegnerla tramite l’interruttore generale, nello stesso modo quando ci sono luci spente, è possibile accenderle con questo interruttore. Per fare questo, si aggiungono due eventi personalizzati in più alla lampada: turnOn e turnOff. Attraverso una logica nell’evento changeState si decide quale evento personalizzato usare:
    Copia codice
    
    $('.lightbulb')
        .bind('changeState', function(e) {
            var $light = $(this);
            if ($light.hasClass('on')) {
                $light.trigger('turnOff');
            } else {
                $light.trigger('turnOn');
            }
        })
        .bind('turnOn', function(e) {
            $(this).removeClass('off').addClass('on');
        })
        .bind('turnOff', function(e) {
            $(this).removeClass('off').addClass('on');
        });
    $('.switch, .clapper').click(function() {
        $(this).parent().find('.lightbulb').trigger('changeState');
    });
    $('#master_switch').click(function() {
        if ($('.lightbulb.on').length) {
            $('.lightbulb').trigger('turnOff');
        } else {
            $('.lightbulb').trigger('turnOn');
        }
    });
    
    Si noti come il comportamento dell’interruttore generale è stato collegato all’interruttore, mentre il comportamento delle lampade appartenengo alle lampade.

    Se siete abituati alla programmazione orientata agli oggetti, è possibile pensare gli eventi personalizzati come metodi degli oggetti. In generale, l’oggetto che appartiene al metodo si crea dal selettore jQuery. Vincolare l’evento personalizzato changeState a tutti gli elementi $(‘.light’) è simile ad avere una classe chiamata Light con un metodo changeState, e poi istanziare nuovi oggetti Light per ogni elemento.
    Ricapitolando:. $.fn.bind e $.fn.trigger
    ⤽
    Nel mondo di eventi personalizzati, ci sono due metodi importanti di jQuery:. $.fn.bind e $.fn.trigger. Ne capitolo dedicato agli eventi è stato spiegato l’uso di questi due metodi per lavorare con gli eventi dell’utente, in questo capitolo è importante ricordare due punti:

    • Il metodo $.fn.bind prende come argomenti un tipo di evento e una funzione di gestione degli eventi. Opzionalmente, può ricevere informazioni associate all’evento come secondo argomento, spostando come terzo argomento la funzione gestore degli eventi. Qualunque informazione passata sarà disponibile alla funzione attraverso della proprietà data dell’oggetto dell’evento. A sua volta, la funzione del gestore degli eventi riceve l’oggetto dell’evento come primo argomento.
    • Il metodo $.fn.trigger prende come argomenti il tipo di evento e facoltativamente può prendere un array di valori. Questi valori saranno passati alla funzione del gestore degli eventi come argomentidopo dell’oggetto dell’evento.

    Di seguito è riportato un esempio d’uso di $.fn.bind e $.fn.trigger in cui si utilizza le informazioni personali in entrambi i casi:

    Copia codice
    
    $(document).bind('myCustomEvent', { foo : 'bar' }, function(e, arg1, arg2) {
        console.log(e.data.foo); // 'bar'
        console.log(arg1); // 'bim'
        console.log(arg2); // 'baz'
    });
    $(document).trigger('myCustomEvent', [ 'bim', 'baz' ]);
    
    Un esempio di applicazione
    ⤽

    Per dimostrare la potenza di eventi personalizzati, svilupperà un semplice strumento per la ricerca di Twitter. Questo strumento offrirà diversi modi per effettuare una ricerca dall’utente: inserirendo il termine da ricercare in una casella di testo o consultando i “temi caldi” di Twitter.
    I risultati di ciascun termine verranno visualizzati in un contenitore di risultati; questi risultati si potranno espandere, comprimere, aggiornare e rimuovere, singolarmente o l’insieme.

    l risultato finale dell’applicazione sarà la seguente:
    Iniziazione

    ⤽
    Inizia con un HTML di base:
    Copia codice
    
    <h1>Twitter Search</h1>
    <input type="button" id="get_trends"
        value="Load Trending Terms" />
    <form>
        <input type="text" class="input_text"
            id="search_term" />
        <input type="submit" class="input_submit"
            value="Add Search Term" />
    </form>
    <div id="twitter">
        <div class="template results">
            <h2>Search Results for
            <span class="search_term"></span></h2>
        </div>
    </div>
    
    L’HTML ha un contenitore (#twitter) per il widget, un modello per i risultati (nascosto con i CSS) e un semplice modulo in cui l’utente può digitare il termine di ricerca.

    Ci sono due tipi di elementi su cui agire: il contenitore di risultati e il contenitore Twitter.

    I contenitori di risultati è cuore dell’applicazione. Si creerà un’estensione per preparare ogni contenitore una volta che questo viene aggiunto al contenitore Twitter. Inoltre, tra le altre cose, l’estensione vincolerà gli eventi personalizzati per ogni contenitore e aggiungerà, in alto a destra di ogni contenitore, pulsanti che eseguiranno azioni. Ogni contenitore di risultati dovrà avere i seguenti eventi personalizzati:
    refresh

    ⤽
    Segnala che l’informazione del contenitore si sta aggiornando e spara la petizione che cerca i dati correlato al termine di ricerca.
    populate
    ⤽
    Ricevere l’informazione in JSON e l’utilizza per riempire il contenitore.
    remove
    ⤽
    Rimuove il contenitore dalla pagina dopo che l’utente conferma l’azione. Tale conferma può essere omessa se si passa true come secondo parametro al gestore degli eventi. L’evento rimuove anche il termine associato nel contenitore di risultati dell’oggetto globale che contiene i termini di ricerca.
    collapse
    ⤽
    Aggiunge una classe al contenitore, il quale nesconderà il risultato attraverso i CSS. Cambierà anche il testo del pulsante da “Colapse” a “Expand”.
    expand
    ⤽
    Rimuovere la classe al contenitore che aggiunge l’evento collapse. Cambierà anche il testo del pulsante da “Expand” a “Colapse”.
    Inoltre, l’estensione è responsabile per l’aggiunta dei pulsanti di azione al contenitore, vincolando un evento click per ogni pulsante e utilizzando la classe di ogni item per determinare quale evento personalizzato verrà eseguito su ogni contenitore di risultati.
    Copia codice
    
    $.fn.twitterResult = function(settings) {
        return this.each(function() {
            var $results = $(this),
                $actions = $.fn.twitterResult.actions =
                    $.fn.twitterResult.actions ||
                    $.fn.twitterResult.createActions(),
                $a = $actions.clone().prependTo($results),
                term = settings.term;
            $results.find('span.search_term').text(term);
            $.each(
                ['refresh', 'populate', 'remove', 'collapse', 'expand'],
                function(i, ev) {
                    $results.bind(
                        ev,
                        { term : term },
                        $.fn.twitterResult.events[ev]
                    );
                }
            );
            // utilizza la classe di ogni azione per
            // determinare quale evento si svolgerà
            // nel riquadro dei risultati
            $a.find('li').click(function() {
                // passa l'elemento <li> cliccato
                // sulla funzione in modo da poterlo
                // manipolare, se necessario
                $results.trigger($(this).attr('class'), [ $(this) ]);
            });
        });
    };
    $.fn.twitterResult.createActions = function() {
        return $('<ul class="actions" />').append(
            '<li class="refresh">Refresh</li>' +
            '<li class="remove">Remove</li>' +
            '<li class="collapse">Collapse</li>'
        );
    };
    $.fn.twitterResult.events = {
        refresh : function(e) {
               // indica che i risultati sono
               // in fase di aggiornamento
            var $this = $(this).addClass('refreshing');
            $this.find('p.tweet').remove();
            $results.append('<p class="loading">Loading ...</p>');
            // ottiene le informazioni da Twitter
            // in formato jsonp
            $.getJSON(
                'http://search.twitter.com/search.json?q=' +
                    escape(e.data.term) + '&rpp=5&callback=?',
                function(json) {
                    $this.trigger('populate', [ json ]);
                }
            );
        },
        populate : function(e, json) {
            var results = json.results;
            var $this = $(this);
            $this.find('p.loading').remove();
            $.each(results, function(i,result) {
                var tweet = '<p class="tweet">' +
                    '<a href="http://twitter.com/' +
                    result.from_user +
                    '">' +
                    result.from_user +
                    '</a>: ' +
                    result.text +
                    ' <span class="date">' +
                    result.created_at +
                    '</span>' +
                '</p>';
                $this.append(tweet);
            });
            // indica che i risultati
            // sono già stati aggiornati
            $this.removeClass('refreshing');
        },
        remove : function(e, force) {
            if (
                !force &&
                !confirm('Rimuovere pannello per il termine ' + e.data.term + '?')
            ) {
                return;
            }
            $(this).remove();
            // indica che si non avrà
            // un pannello per il termine
            search_terms[e.data.term] = 0;
        },
        collapse : function(e) {
            $(this).find('li.collapse').removeClass('collapse')
                .addClass('expand').text('Expand');
            $(this).addClass('collapsed');
        },
        expand : function(e) {
            $(this).find('li.expand').removeClass('expand')
                .addClass('collapse').text('Collapse');
            $(this).removeClass('collapsed');
        }
    };
    
    Il contenitore Twitter, ha solo due eventi personalizzati:
    getResults
    ⤽
    Riceve un termine di ricerca e verifica se c’è un contenitore di risultati per il termine. Se non esiste, aggiunge un contenitore utilizzando il modello dei risultati, lo configura utilizzando l’estensione $.fn.twitterResult (vedi sopra) e quindi esegue l’evento refresh per caricare correttamente i risultati. Infine, salva il termine di ricerca per evitare di dover richiedere i dati per il termine..
    getTrends
    ⤽
    Consulta a Twitter l’elenco delle prime 10 “parole calde”, interagisce con loro ed esegue l’evento getResults su ciascuno, in modo che si aggiunga un contenitore di risultati per ciascun termine.
    Collegamenti nel contenitore Twitter:
    Copia codice
    
    $('#twitter')
        .bind('getResults', function(e, term) {
            // si verifica che non ci sia
            // un contenitore per il termine
            if (!search_terms[term]) {
                var $this = $(this);
                var $template = $this.find('div.template');
                // fa una copia del modello div e la inserisce
                // come il primo contenitore di risultati
                $results = $template.clone().
                    removeClass('template').
                    insertBefore($this.find('div:first')).
                    twitterResult({
                        'term' : term
                    });
                // carica il contenuto utilizzando
                // l'evento personalizzato "refresh"
                // vincolato al contenitore dei risultati
                $results.trigger('refresh');
                search_terms[term] = 1;
            }
        })
        .bind('getTrends', function(e) {
            var $this = $(this);
            $.getJSON('http://search.twitter.com/trends.json?callback=?', function(json) {
                    var trends = json.trends;
                    $.each(trends, function(i, trend) {
                        $this.trigger('getResults', [ trend.name ]);
                    });
                });
        });
    
    Finora, si è scritto un sacco di codice che non fa nulla, che non è male. Si sono specificati tutti i comportamenti che si desiderano per gli elementi essenziali e si è creato una base solida per creare rapidamente l’interfaccia.

    Di seguito, si collega la casella di ricerca e pulsante per caricare i “temi caldi”. Nella casella, il termine digitato viene catturato e passato, allo stesso tempo che si esegue getResults. D’altra parte, cliccando sul pulsante per caricare i “temi caldi”, si esegue l’evento getTrends:

    Copia codice
    
    $('form').submit(function(e) {
        e.preventDefault();
        var term = $('#search_term').val();
        $('#twitter').trigger('getResults', [ term ]);
    });
    $('#get_trends').click(function() {
        $('#twitter').trigger('getTrends');
    });
    
    Aggiugendo pulsanti con un ID apropriato, è possibile rimuovere, collassare, espandere e aggiornare tutti i contenitori di risultati, allo stesso tempo. Per il pulsante che rimuove il contenitore, notare che si sta passando true al gestore di eventi come il secondo argomento, indicando che non si vuole una conferma da parte dell’utente per rimuovere il contenitore.
    Copia codice
    
    $.each(['refresh', 'expand', 'collapse'], function(i, ev) {
        $('#' + ev).click(function(e) { $('#twitter div.results').trigger(ev); });
    });
    $('#remove').click(function(e) {
        if (confirm('Remove all results?')) {
            $('#twitter div.results').trigger('remove', [ true ]);
        }
    });
    
    Conclusione
    ⤽
    Gli eventi personalizzati rappresentano un modo nuovo di pensare il codice: essi sottolineano l’obiettivo di un comportamento e non nell’elemento che lo attiva. Se si prende il tempo dall’inizio per spiegare le parti della vostra applicazione, così come i comportamenti che queste parti hanno bisogno di esibire, gli eventi personalizzati forniscono un potente strumento per “parlare” con quelle parti, sia uno alla volta o in massa.

    Una volta che i comportamenti sono stati descritti, diventa banale da eseguire da qualunque luogo, consentendo la creazione rapida e la sperimentazione di opzioni di interfaccia. Infine, eventi personalizzati sono in grado di migliorare la leggibilità del codice e la sua manutenzione, rendendo chiara la relazione tra un elemento e il suo comportamento.

    È possibile visualizzare l’applicazione completa dei files demos/custom-events/custom-events.html e demos/custom-events/js/custom-events.js che compongono questo libro.

    Crediti
    ⤽
    Fondamentali di jQuery
    ⤽
    Di Rebecca Murphey
    http://github.com/rmurphey/jqfundamentals
    Con il contributo di James Padolsey, Paolo Irish e gli altri. Per una storia completa dei contributi visitare il repository GitHub.
    Copyright © 2011

    Concesso in licenza da Rebecca Murphey sotto la Creative Commons Attribution-Share Alike 3.0 United States license Siete liberi di copiare, distribuire, trasmettere, e remix questo lavoro, a condizione di attribuire l’opera a Rebecca Murphey come l’autore originale e il repository di riferimento GitHub per il lavoro. Se alteri, trasformi o sviluppi quest’opera, puoi distribuire l’opera risultante solo con la stessa, simile o di una licenza compatibile. Una delle condizioni di cui sopra può essere revocata se si ottiene il permesso del detentore del copyright. Ogni volta che usi o distribuisci quest’opera, devi farlo secondo i termini della licenza di quest’opera. Il modo migliore per farlo è con un link per la licenza.