JQuery

Da Skypedia.
Jquery.gif
JQuery è un framework Javascript creato da John Resig nel 2006 (il primo post che aprì la strada a JQuery). JQuery è adatto sia allo sviluppatore avanzato DOM/Javascript che al neofita che non conosce niente di Javascript. La filosofia alla base di JQuery è di mantenere sempre il codice semplice e conciso. Bisogna avere a portata di mano codice che possa essere riusabile e semplice da capire e debuggare.


La programmazione

Il codice DOM Javascript senza jQuery:

var external_links = document.getElementById('external_links');
var links = external_links.getElementsByTagName('a');
for (var i=0;i < links.length;i++) {
    var link = links.item(i);
    link.onclick = function() {
        return confirm('You are going to visit: ' + this.href);
    };
}

Il codice jQuery

	
$('#external_links a').click(function() {
    return confirm('You are going to visit: ' + this.href); // Il + serve a concatenare le stringhe
});

Come potrete osservare il "reperimento" degli oggetti DOM è fatto da jQuery direttamente con l'utilizzo della funzione $ seguito da una parentesi che racchiude gli elementi fra apici ordinati secondo la gerarchia. In pratica gli ID saranno identificati da un #NOME_ID, e le classi da un .CLASSE. Gli elementi vengono quindi selezionati partendo dal contenitore. Ad esempio tutti gli oggetti a che stanno dentro un div con id "menu" possono essere selezionati con jQuery così:

$('div#menu a')

Questo comportamento è permesso da jQuery grazie all'utilizzo dei cosiddetti #I selettori, che in questo caso agiscono sugli elementi base della pagina.

L'utilizzo di jQuery inoltre elimina la necessità dei continui loop per scorrere gli elementi come accadeva con Javascript. Non si deve più andare a programmare un ciclo for per tutta la lunghezza del vettore contenente gli elementi DOM su cui agire.


La funzione $()

La funzione $() è la funzione più potente di jQuery - essa viene usata quasi sempre per selezionare gli elementi nel documento. Questa funzione proviene da uno standard de facto creato dal concorrente Prototype che aveva definito $ come alias della funzione ormai inflazionata document.getElementById(). Il simbolo del dollaro $ è anche una scorciatoia per la vera funzione che esso rappresenta. In effetti per accedere a tutti gli elementi wrapper di jQuery si potrebbe utilizzare il più "logico" jQuery(). Nell'esempio precedente essa scorreva gli elementi del CSS che abbiamo inserito in ordine di gerarchia e abbiamo ricevuto come output il vettore contente questi ultimi. Chiunque abbia familiarità con i selettori CSS amerà questa sintassi, che sta alla base dell'idea stessa di jQuery. Ogni elemento jQuery in pratica corrisponde ad un vettore corredato di moltissime funzioni jQuery.

L'utilizzo comune della funzione $() è quello di passare ad essa un qualsiasi elemento o un vettore di elementi per far sì che jQuery costruisca un wrapper che contenga il tutto e ci dia la possibilità di richiamare metodi e funzioni propri del framework. Normalmente si tende a richiamare le funzioni su comportamenti di window; ad esempio al caricamento.

Si può anche creare un elemento utilizzando una stringa, il risultato è un elemento jQuery che contiene quest'ultimo

$('<p></p>') // EQUIVALE A: jQuery('<p></p>')
    .html('Ciao Mondo!')
    .css('background', 'yellow')
    .appendTo("body");

Nell'esempio sopra abbiamo utilizzato il #Method chaining aggiungendo al body con appendTo un CSS e un paragrafo con il testo Ciao Mondo!.


Evitare i conflitti

Se si sta utilizzando qualche altro framework javascript che inflaziona il simbolo $ si possono pensare di evitare i conflitti richiamando la funzione jQuery.noConflict(). Si può anche evitare ogni conflitto scrivendo degli script che siano praticamente chiusi all'esterno e marcandoli espressamente come funzioni jQuery:

(function($) {
    // Dentro questo blocco $ è un riferimento a jQuery
})(jQuery);

Con noConflict possiamo utilizzare una funzione alias del problematico dollaro:

var $j = jQuery.noConflict();

$j(function(){

    $j("#sidebar li a").hover(function(){
        $j(this).stop().animate({
            paddingLeft: "20px&"
        }, 400);
    }, function() {
        $j(this).stop().animate({
            paddingLeft: 0
        }, 400);
    });

});

I selettori

  • Selettori base: permettono di selezionare gli elementi in base a caratteristiche chiave come l'id, il tag name o la classe di appartenenza;
// seleziona tutti i link della classe 'prova' che sta dentro un div
$("div.prova[a]");
  • selettori gerarchici: permettono di selezionare gli elementi in base alla organizzazione gerarchica della pagina;
// seleziona tutti gli elementi figlia di una lista non ordinata
$("ul/li")
 /* E' valido anche: */ 
$("ul > li")
  • filtri base: permettono di filtrare gli elementi in base alla posizione e all'ordine che essi hanno nella pagina;
$("a") //seleziono i link nella pagina
   .filter(".clickme") // filtro quelli che hanno la classe "clickme"
     .click(function(){  // sul click eseguo una funzione di callback
       alert("Stai per lasciare la pagina."); // avverto l'utente con un popup che sta per abbandonare la pagina
     })
   .end()
   .filter(".hideme") // filtro sulla classe "hideme"
     .click(function(){
       $(this).hide(); // nascondo questo elemento
       return false;  // prevengo l'azione sul click che mi porterebbe ad abbandonare la pagina
     })
   .end();
<!-- L'HTML per lo script sopra --> 
<a href="http://fsf.org" class="clickme">Io lascio un messaggio quando esci dalla pagina</a>
<a href="http://linux.com/" class="hideme">Clicca per nascondermi!</a>
<a href="http://debian.org/">Io sono un link normale</a>
  • filtri sul contenuto: permettono di filtrare gli elementi in base al loro contenuto (sia testo che non);
  • filtri sulla visibilità: permettono di filtrare gli elementi in base alla loro visibilità nella pagina;
//nasconde tutti i div che sono al momento visibili 
$("div:visible").hide();
  • filtri sugli attributi: permettono di filtrare gli elementi in base ad alcune caratteristiche dei loro attributi;
// selezionare tutti i link esterni (che iniziano con http://
jQuery('a[@href^="http://"]')
  • filtri sugli elementi child: permettono di filtrare gli elementi in base agli elementi child del padre che li contiene;
  • selettori per form: permettono di selezionare gli elementi in base al loro impiego all'interno di form;
  • filtri per form: permettono di filtrare gli elementi appartenenti ai form in base al loro stato attuale.

Usare al meglio i selettori

Nella maggior parte dei casi conviene preferire gli ID alle classi, visto che nei browser un po' più vecchi, come IE 7 o Firefox 2 la selezione di tutte le classi in un DOM risulta decisamente più lenta.

$("#mioElemento"); //da preferire
$(".miaClasse"); //da evitare
$("div.miaclasse"); //compromesso accettabile

Analizzando il funzionamento della funzione di selezione di jQuery. Nei browser più vecchi una query di questo tipo:

$("p#header strong");

carica tutti gli elementi strong in un array. Successivamente cerca tra i generitori di ogni nodo caricato e rimuove quelli in cui p#header non viene trovato. Immaginate quanti elementi strong può contenere una pagina e capirete perché non è conveniente una query di questo tipo. Questo avviene perché perché il selettore più interno viene utilizzato con una maggiore precedenza. Quindi la selezione avviene da destra a sinistra e poi si va via via scartando. Si può allora ovviare al problema utilizzando una selezione che qualifichi maggiormente i selettori più significativi in questi due modi:

$("strong", $("p#header")); // prima seleziono p#header e poi cerco gli elementi strong
$("p#header").find("strong"); // metodo alternativo.

Depending on your document, the query can be optimized by retrieving the best-qualified selector first. It can then be used as a starting point for child selectors, e.g.


Approfondimenti sui selettori

  1. http://docs.jquery.com/DOM/Traversing/Selectors
  2. Come selezionare tutto quello che si vuole (esempio pratico)

Creare una funzione

A volte capita di non riuscire a trovare il modo di fare le cose semplici per un programmatore, e in jQuery una di queste cose, a prima vista, è quella di trovare un manuale di riferimento orientato al senso comune di chi scrive codice. In questo senso risulta difficoltoso trovare una guida di riferimento che ci illustri la sintassi corretta per la creazione di una qualsiasi funzione in jQuery. Un esempio di funzione può essere il seguente:

jQuery.caricaImmagini = function()
{
     for(var i = 0; i<arguments.length; i++) // un ciclo for in stile Java
     {
          /* 
           * Seleziono le immagini nella pagina e ne prendo gli attributi src */
          jQuery("<img>").attr("src", arguments[i]);
     }
}

Adesso .caricaImmagini è una funzione a tutti gli effetti che possiamo richiamare dopo un ready.

Un altro modo per creare una funzione è il seguente:

function miaFunzione()
{
      $("selecttore").click();
};
Adesso la funzione è richiamabile tramite il suo nome (miaFunzione).


Le funzioni load e ready

L'utilizzo normale dell'elemento window è quello di richiamare una funzione al suo caricamento in questo modo:

window.onload = function() {
    // Esegue la funzione solo dopo il caricamento della pagina
};

Utilizzando jQuery invece:

$(window).load(function() {
    // Esegue solo quando l'intera pagina è stata scaricata
});


$(document).ready()

Il problema in questo genere di codice è che l'onload implica il caricamento di tutta la pagina e poi la chiamata alla funzione e ciò comporta un rallentamento notevole delle prestazioni dello script soprattutto quando di mezzo ci sono immagini. Se, ad esempio, si volesse agire su una galleria di foto ci si accorgerebbe di quanto lento è il caricamento del codice javascript legato al load dell'intero documento. Nella maggior parte dei casi, però, ci si può accontentare del caricamento del solo HTML, senza perder tempo con i vari elementi multimediali quali immagini, suoni o video. Per far ciò jQuery dispone di una utilissima funzione: ready.

$(document).ready(function() {
    // Esegue la funzione solo quando tutto l'HTML è ready
});

Per richiamare questa funzione in maniera più agevole jQuery ha predisposto un'utile scorciatoia che ci consente di guadagnare tempo e fatica nella scrittura di un qualsiasi script. Basterà infatti passare la funzione che deve attendere il ready della pagina alla funzione $() e il gioco è fatto:

$(function() {
    // Esegue mentre la pagina si sta ancora scaricando del tutto
});


Method chaining

La principale innovazione portata da questo framework è il cosidetto method chaining o chainability (traducibile, ma anche no, concatenabilità). Tutti i metodi di jQuery, infatti, ritornano lo stesso oggetto sul quale è stato invocato il metodo definito dal framework; così facendo si possono concatenare metodi in un modo molto affine alla teoria della programmazione ad oggetti. Giusto per fare un esempio:

$('div#Contenuto').addClass('selezionata').html('quello che ti aggrada io scrivo').width(100);


Attributes

Come in Javascript, anche in jQuery è possibile modificare gli attributi [1] di qualsiasi elemento come un link che abbia un determinato attributo title o href. Le funzioni generiche che fanno uso degli attributes utilizzano il nome dello stesso come parametro:

$('a.google').attr('href','http://www.google.com')


Creare un plugin

Capita spesso di dover creare un plugin per rendere una funzionalità accessibile da molte pagine in maniera trasparente e prevenendo la modifica del proprio codice da parte di altri script contenuti nelle varie pagine del sito. Si può anche volere redistribuire il proprio lavoro in modo tale da condividerlo con gli altri sviluppatori e utilizzatori di jQuery. Farlo non è difficile e può anzi risultare molto più comodo rispetto allo scrivere gli script inline. Per creare un plugin dobbiamo:

  1. Trovare un nome per il plugin, per esempio chiamiamo il nostro plugin di prova "testPlugin";
  2. creare un file nominandolo jquery.[nomeDelPlugin].js (nel nostro caso jquery.testPlugin.js);
  3. creare uno o più metodi per il plugin estendendo l'oggetto base jQuery, ad esempio:
jQuery.fn.testPlugin = function() { // Come al solito si può utilizzare anche $.fn.testPlugin = function()
	/* 
         * Codice da eseguire nel Plugin
         */
};

Per evitare i conflitti possiamo definire il plugin in questo modo:

(function($) {
    $.fn.testPlugin = function() {
    };
})(jQuery);

Possiamo anche definire delle funzioni all'interno del file che possano poi essere richiamate dal plugin, ciò può essere molto d'aiuto anche per mantenere delle variabili e delle funzioni locali:

(function($) {
    $.testPlugin = {
        width: 5,
	cacolaQualcosa = function() { ... },
	verificaDipendenze = function() { ... }
    }

    $.fn.testPlugin = function() {
        $.testPlugin.verificaDipendenze(valore); // Richiamo la funzione all'interno di testPlugin
    };
})(jQuery);

In questo modo possiamo creare delle opzioni di default che possono essere cambiate dall'utente al momento della chiamata. Ad esempio:

(function($) {
    $.fn.testPlugin = function(opzioni) {
         var settings = {
		valore: 5,
		nome: "Pippo",
		dimensione: 655
         };
         if(opzioni) { // verifico che siano state passate delle opzioni ed estendo la variabile settings, con le opzioni passate
		jQuery.extend(settings, opzioni);
	}
    };
})(jQuery);

Adesso possiamo richiamare il plugin con o senza opzioni:

$("...").testPlugin({
   valore: 10,
   dimensione: 400
});


Modello per creare un plugin jQuery

Volendo creare un nuovo plugin jQuery la soluzione più conveniente è quella di farlo partendo da un modello già completo di tutti gli elementi base per la creazione di un nuovo componente della libreria fn di jQuery.

(function($) {

    $.fn.mioPlugin = function(method) {

        var defaults = {
            prova: 'test'
        }

        var settings = {}

        var methods = {

            init : function(options) {
                settings = $.extend({}, defaults, options)
                return this.each(function() {
                    var element = $(this);
                    // Il codice da eseguire su element va qui. Esso agirà su ogni singolo elemento a cui si fa riferimento tramite un composite
                });
            },

            qualsiasi_public_method: function() {
                // Il codice del metodo
            }

        }

        var helpers = {

            qualsiasi_private_method: function() {
                // Il codice del metodo privato accessibile da helpers
            }

        }

        if (methods[method]) {
            return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));
        } else if (typeof method === 'object' || !method) {
            return methods.init.apply(this, arguments);
        } else {
            $.error( 'Method "' +  method + '" does not exist in pluginName plugin!');
        }

    }

})(jQuery);

Ajax diventa semplice con JQuery

Tutto ciò che era semplice con Ajax diviene ancora più semplice con JQuery e quello che era complesso adesso è divenuto comprensibile da tutti. Un utilizzo comune di Ajax è quello di caricare del codice HTML in una specifica area della pagina senza che venga richiesto un nuovo caricamento dell'intera pagina. Si fa quindi una richiesta asincrona e ci si attende un risultato in maniera trasparente e veloce per l'utente. Per fare questo con JQuery selezioniamo l'elemento con la funzione $() e utilizziamo la funzione load() per il caricamento con Ajax.

$('div#contenutoAjax').load('CoseVarieCaricateConAjax.html');

Spesso si ha il bisogno di inviare dei parametri al server e ciò può essere fatto con la funzione $.post(). Fare il get è oltremodo semplice con la funzione $.get(). Queste funzioni, come moltre altre di JQuery supportano i callback. Possiamo quindi inviare un post e avvertire l'utente quando i suoi dati sono stati salvati

	
// Inviare dei dati utilizzando Ajax
$.post('save.cgi', {
    text: 'Del testo',
    number: 222
}, function() {   // Il callback
    alert('I tuoi dati sono al sicuro adesso.');
});


La funzione $.ajax()

Se si vuole una maggiore padronanza di Ajax e delle sue funzionalità (cosa che comporta una maggiore complessità di gestione) bisogna affidarsi alla funzione $.ajax(). Si può specificare il tipo di dato che si sta utilizzando con dataType; esso potrà essere XML, HTML, script, o Json e jQuery automaticamente preparerà il risultato per la funzione da chiamare tramite callback. Possono anche essere specificati altri parametri utili come beforeSend, error, success o utilizzare come al solito delle funzioni di callback personalizzate per dare all'utente un feedback continuo di ciò che si sta facendo e creando la sensazione che ci si trovi di fronte ad una applicazione desktop invece che una webapplication, il tutto in stile web2.0. Si possono specificare molti parametri per monitorare l'avanzamento della richiesta Ajax come il timeout o l'ultimo stato di modifica della pagina.

$.ajax({
    url: 'documento.xml',
    type: 'GET',
    dataType: 'xml',
    timeout: 1000,
    error: function(){ // Sull'errore invoco una funzione
        alert('Errore durante il caricamento del documento XML');
    },
    success: function(xml){
        // Eseguo le modifiche al file XML
        $(xml).find('elemento').each(function(){
        var item_text = $(this).text();

        $('<li></li>')
            .html(item_text)
            .appendTo('ol');
        });
    }
});


Animazioni ed effetti

Con jQuery le animazioni risultano semplici ed immediate. La prima cosa da fare è sempre quella di selezionare l'elemento della pagina su cui agire e poi di utilizzare la funzione animate(), che non fa altro che cambiare gli attributi CSS dell'elemento nel tempo dando l'impressione visiva che avrebbe un'animazione FLASH. Ad esempio possiamo far crescere un elemento di una pagina assegnandogli altezza e larghezza a nostro piacere:

$('#cresci').animate({ height: 500, width: 500 }, "slow", function(){
    alert("L'elemento sta crescendo!");
});

Vediamo di sbalordire tutti con un animate concatenato che dà un effetto di animazione che sembra richiedere ben altro rispetto al solo HTML e Javascript:

$(document).ready(function(){

	$(".run").click(function(){

	  $("#box").animate({opacity: "0.1", left: "+=400"}, 1200)
	  .animate({opacity: "0.4", top: "+=160", height: "20", width: "20"}, "slow")
	  .animate({opacity: "1", left: "0", height: "100", width: "100"}, "slow")
	  .animate({top: "0"}, "fast")
	  .slideUp()
	  .slideDown("slow")
	  return false;

	});

});

L'esempio reale di questo script lo trovate qui [2]. Lo script sopra non fa altro che partire quando si clicca su Run e dare un animate al div con ID box. Il primo animate della catena setta opacità a 0.1 (fa quasi svanire il box) e lo fa mentre lo sposta gradualmente fino a raggiungere 400 pixel da sinistra (left: "+=400"), il tutto in 1200 millisecondi. La catena continua con altri tre animate che aumentano l'opacità e variano la grandezza dell'oggetto. L'ultimo animate riporta sopra il box. Arrivato in posizione il blocchetto fa uno SlideUp e poi uno SlideDown (si accartoccia e si dispiega dando l'idea di una sorta di impatto). Il return false impedisce al browser di andare al link dell'ancora che abbiamo appena premuto. Tutto ciò come si vede è più facile a dirsi che a farsi.

Si possono utilizzare anche le funzioni show() e hide() che consentono di far apparire e scomparire un qualsiasi elemento con una certa velocità. Si possono utilizzare anche gli effetti dati dalle funzioni fadeIn() o fadeOut() per far entrare o uscire di scena un elemento dalla pagina.

jQuery e Firebug

Se siete dei programmatori web avrete di certo voglia di provare i vostri script e il vostro codice lato client direttamente dentro la finestra del vostro browser. Il modo per farlo è quello di installare un'estensione per Firefox assolutamente indispensabile: Firebug.

Firebug integrates with Firefox to put a wealth of development tools at your fingertips while you browse. 
You can edit, debug, and monitor CSS, HTML, and JavaScript live in any web page...

Per manipolare le pagine web al volo con jQuery e Firebug non ci resta che aggiungere il bookmarklet per jQuery (jQuerify) e andare ad editare direttamente la console Javascript di Firebug per vedere come la pagina si stia comportando con gli script (è disponibile anche una versione aggiornata e migliorata di questo bookmarklet [3]).

Google-jquerified.png

jQuery ed Aptana

Aptana è un IDE per la programmazione web, del tutto simile al famosissimo Eclipse. Vediamo come fare per creare un nuovo progetto jQuery con Aptana Studio.

  1. Crea un nuovo progetto per jQuery
    1. Seleziona dal menu file New > Project... (si apre un wizard per il progetto)
    2. Selezionare General Web Project
    3. Immettere il nome del progetto
    4. Dal menu di selezione delle librerie Javascript (o Ajax) da importare selezionare jQuery

Aptana creerà un nuovo progetto che contiene all'interno una cartella lib contenente le librerie jQuery e un file jquery_sample.html come base di partenza per i vostri script jQuery.


Lazy Load e Ghost Load

Il pattern "Lazy Load" corrisponde all’implementazione del design pattern chiamato Proxy. L’obiettivo è di evitare il caricamento di un oggetto finché non sia assolutamente indispensabile e solo allora sarà necessario investire risorse per caricarlo. Nel caso del JavaScript, un'applicazione web generalmente ha bisogno di un set di funzioni che vengono chiamate progressivamente durante l’interazione con l’utente. Applicare il Lazy Load in questo caso significa creare delle funzioni "vuote", senza il loro codice che verrà caricato al momento della loro prima chiamata. Definiamo questa tecnica come Ghost Pattern.

Come fare tutto ciò con jQuery? Ma è semplicissimo; basta utilizzare il plugin "Plugin"

Per registrare un plugin con Plugin:

var plugin = $.plugin.register( url_of_the_file, names_to_register, settings );
 
var plugin = new $.plugin( url_of_the_file, names_to_register, settings );


Suggerimenti

Riconoscere Internet Explorer

Capita spesso di dover riconoscere il browser su cui si sta facendo visualizzare qualcosa per il semplice fatto che questo magari venga visualizzato in modo non standard. Mi è capitato di validare sul sito W3C un intero sito e di non ricevere alcun errore di sintassi XHTML e CSS, ma purtroppo il sito in questione su IE veniva visualizzato in maniera completamente errata. Il problema sta tutto nel supporto al CSS e a varie altre cose. Se siete in queste condizioni vi conviene "scriptare" a parte per IE e allegare il codice con la funzione che segue:

if ($.browser.msie) {
   alert("E così alla fine la Bestia cadde e i miscredenti esultarono.
Ma non tutto era perduto, giacché dalle ceneri sorse un mitico uccello.
L'uccello guardò giù verso i blasfemi, e invocò il fuoco e il
fulmine su di loro. Poiché la Bestia era risorta con rinnovata 
forza, e i seguaci di Mammona si fecero piccoli dall'orrore.");
 }


Risorse