#136 jQuery
- Download:
- source codeProject Files in Zip (111 KB)
- mp4Full Size H.264 Video (14.1 MB)
- m4vSmaller H.264 Video (9.72 MB)
- webmFull Size VP8 Video (25.1 MB)
- ogvFull Size Theora Video (19.4 MB)
Nell’episodio 43 vi abbiamo mostrato come aggiornare più elementi di una pagina mediante la risposta di una richiesta AJAX. Abbiamo usato le librerie di Prototype e il metodo form_remote_for
per fare il submit asincrono e RJS per generare il JavaScript responsabile dell’aggiornamento degli elementi della pagina alla risposta. In questo episodio useremo invece jQuery, anzichè Prototype e RJS, per fare la stessa cosa.
Usando jQuery, non potremo usare RJS o qualsiasi altro metodo helper tipo form_remote_for
fornito da Rails. Se volessimo ancora continuare a usare RJS, esiste un plugin chiamato jRails che riscrive quei metodi per farli andare con jQuery, ma noi useremo jQuery da solo, dal momento che fornisce un modo per scrivere unobtrusive Javascript, migliorando le nostre applicazioni Rails.
Lavoreremo con la stessa applicazione usata in precedenza. La pagina di sotto mostra un prodotto e permette ai consumatori di aggiungere delle recensioni a questo. Quando viene inserita una nuova recensione, compare nella lista delle recensioni, viene aggiornato il testo mostrante il numero di recensioni, la form viene resettata e viene anche mostrato un messaggio flash che ringrazia l’utente per l’aggiunta della recensione.
L’attuale applicazione attualmente invia la pagina al server e la ricarica una volta aggiunto un prodotto. Scriveremo del codice jQuery per rendere l’invio della form e il ricaricamento della pagina con AJAX, senza bisogno di ricaricare tutto.
Aggiungere jQuery alla nostra applicazione
La prima cosa da fare è aggiungere la libreria jQuery alla nostra applicazione. Può essere scaricata dal sito web di jQuery e una volta scaricato, va messo nella cartella public/javascripts
. Poi dobbiamo aggiungere il riferimento a tale libreria nel file di layout dell’applicazione, inserendo la seguente linea nella sezione <head>
:
<%= javascript_include_tag ['jquery-1.3.2', 'application'] %>
Ogni release di jQuery è disponibile in due versioni: una per lo sviluppo ed una miniaturizzata per la produzione. E’ bene usare la versione per lo sviluppo mentre si sviluppa, perchè rende l’eventuale debugging decisamente più semplice rispetto all’altra versione. Così come fatto per il file di jQuery, dovremo anche mettere un riferimento al file application.js
, dal momento che è lì che metteremo il nostro codice jQuery. Si noti che il file jQuery è aggiunto per primo, affinchè sia caricato prima del file JavaScript dell’applicazione.
Aggiunta di unobtrusive JavaScript
Per aggiungere del JavaScript in maniera "unobtrusive" (non invasiva) non vogliamo cambiare significativamente il codice della nostra vista. Piuttosto, useremo jQuery per cambiare il comportamento di elementi della pagina in maniera dinamica. Cominceremo con lo scrivere una funzione che esegua al submit della form:
La nostra form ha come id "new_review". Il codice riportato qui sotto farà sì che tale form sia inoltrata al server mediante AJAX:
$(document).ready(function (){ $('#new_review').submit(function (){ $.post($(this).attr('action'), $(this).serialize(), null, "script"); return false; }); });
La prima riga del codice qui sopra crea una funzione che eseguirà al termine del caricamento del DOM. La seconda riga, invece, trova la nostra form per id
e crea una funzione che eseguirà al submit della form. La terza riga, infine, crea la richiesta AJAX che sarà inviata in POST al server. La funzione $.post
richiede quattro argomenti:
- L’URL a cui inviare i dati, per il quale forniamo il valore dell’attributo
action
della form. - I dati da inviare. Per questo, usiamo il metodo di jQuery
serialize
, che serializzerà gli elementi di form come una serie di coppie chiave / valore. - Una funzione di callback da eseguire al termine della richiesta AJAX, ma che noi non sfrutteremo, per cui per questo attributo forniamo come valore
null
. - La ragione per cui non abbiamo una funzione di callback è che possiamo dire alla funzione che stiamo restituendo del JavaScript che dovrebbe essere eseguito dal browser e lo facciamo proprio fornendo
“script”
come quarto argomento.
Per ulteriori dettagli sulla funzione $.post
si veda la documentazione di jQuery. Alla fine di tutto restituiamo false
, in modo tale che non sia intrapresa l’action di submit di default.
Aggiornamento del controller
Ora che la nostra form invia i dati con AJAX, dobbiamo modificare il nostro controller delle recensioni affinchè possa gestire sia le richieste HTML, sia quelle JavaScript. Al momento salva la nuova recensione e ridirige alla pagina dei prodotti. Un redirect non ha senso nel contesto di richieste JavaScript, per cui la pagina dovrà rispondere in maniera diversa in questi casi. Useremo la respond_to
per impostare due diversi blocchi:
def create @review = Review.create!(params[:review]) flash[:notice] = "Thanks for your review!" respond_to do |format| format.html { redirect_to @review.product } format.js end end
Il blocco js
è vuoto poichè tutto quello che deve fare è semplicemente restituire il JavaScript che creiamo ora. Quest’ultimo risiederà in un file chiamato create.js.erb
nella cartella /app/views/reviews
. Senza jRails non possiamo usare RJS con jQuery, quindi useremo piuttosto un file js.erb
. Per cominciare aggiungiamo un semplice alert
al create.js.erb
per verificare che il nostro codice funziona:
alert('Hello from AJAX');
Prima di provare, c’è un’altra cosa che dobbiamo fare. Così com’è, il codice non può funzionare, e la ragione di ciò è che Rails non conosce quale sia il formato in cui jQuery manda le richieste, per cui assume per default che sia HTML. Dobbiamo far sapere a Rails che manderemo le richieste in formato JavaScript.
Ci sono due modi per farlo.
- Potremmo aggiungere l’estensione
.js
all’URL prodotto dalla richiesta AJAX. - Potremmo usare il metodo
ajaxSetup
di jQuery, per impostare l’header della richiesta, affinchè accetti esclusivamente JavaScript.
application.js
:
jQuery.ajaxSetup({ 'beforeSend': function (xhr) {xhr.setRequestHeader("Accept", "text/javascript")} });
L’aggiunta dell’header notificherà a Rails di chiamare il blocco js
e di restituire il contenuto del file js.erb
. Ora possiamo aggiornare la pagina e provare ad aggiungere una recensione.
La risposta dalla create.js.erb nel browser.
Aggiornamento della pagina
L’alert viene mostrato, per cui in effetti ci viene restituito il file create.js.erb
. Ora dunque possiamo sostituire il provvisorio alert con l’opportuno codice jQuery che aggiorni la pagina a seguito dell’inserimento di una nuova recensione. Ci sono quattro cose che vogliamo fare:
Per prima cosa, vogliamo aggiungere un messaggio flash alla pagina che ringrazi l’utente per l’inserimento dell’opinione. Lo facciamo aggiungendo un div
prima della form:
$('#new_review').before('<div id="flash_notice"><%= escape_javascript(flash.delete(:notice)) %></div>');
Per aggiungere del contenuto dinamico, usiamo semplicemente tag erb
all’interno del JavaScript.
Useremo la funzione escape_javascript
per rendere sicuro l’output proveniente dall’erb
JavaScript. Si noti che stiamo richiamando il flash.delete
per rimuovere il messaggio flash, in modo che questi non si ripresenti alla successiva request.
L’elemento che contiene il contatore di recensioni dovrà a sua volta essere aggiornato. Ha un id
denominato reviews_count
e si può usare il metodo di jQuery html
per aggiornarne il contenuto:
$('#reviews_count').html('<%= pluralize(@review.product.reviews.count, "Review") %>');
Poi vogliamo aggiungere la nuova recensione all’elenco. Le recensioni sono mostrate all’interno di una lista ordinata con id
di nome reviews
. Ciascuna recensione è mostrata come elemento di lista mediante un partial. Per aggiungere la nostra nuova opinione, possiamo renderizzare in partial per il nostro nuovo elemento e aggiungerlo alla lista:
$('#reviews').append("<%= escape_javascript(render(:partial => @review)) %>");
Infine, ripuliamo la form:
$('#new_review')[0].reset();
La funzione jQuery, $
, restituisce un oggetto jQuery. Per ottenere l’effettivo elemento DOM che rappresenta, prandiamo il primo elemento dall’array. Poi invochiamo su di esso il metodo reset()
per sbiancare la form:
Estendere jQuery
Per concludere l’episodio, vi mostreremo come sia facile aggiungere le vostre funzioni proprietarie a jQuery. Attualmente abbiamo sviluppato un po’ di codice jQuery che esegue al submit della form:
$('#new_review').submit(function (){ $.post($(this).attr('action'), $(this).serialize(), null, "script"); return false; });
Se volessimo fattorizzare questa logica per poterla applicare a diverse form nella nostra applicazione, potremmo estrarre questo codice in una nuova funzione jQuery, in modo tale da poter chiamare:
$('#new_review').submitWithAjax();
piuttosto. jQuery è semplice da estendere con funzioni custom. Possiamo creare la nostra nuova funzione, scrivendo:
jQuery.fn.submitWithAjax = function () { this.submit(function () { $.post($(this).attr('action'), $(this).serialize(), null, "script"); return false; }); };
Questo è tutto ciò che dovevamo fare. Ora possiamo fare il submit asincrono di qualunque form, chiamando submitWithAjax
su di essa.