Indicatori di caricamento con RichFaces 4 e jQuery BlockUI

La novità più importante di RichFaces 4 è stata sicuramente il passaggio da Prototype a jQuery: questo cambiamento ha portato una maggiore leggerezza di tutto il framework e molti altri vantaggi. Per gli sviluppatori si aprono molti scenari interessanti in quanto i numerosi plugin di jQuery presenti in rete possono essere integrati facilmente in una web app. In questo post vediamo come sfruttare jQuery BlockUI per creare facilmente un indicatore di caricamento associato a una chiamata ajax.

a4j:status

Il tag status della tag library a4j permette di eseguire un codice javascript o mostrare un elemento html in corrispondenza di una chiamata ajax. Un esempio classico (presente anche nello showcase di Richfaces 4.1) è una gif animata che compare cliccando su un button o durante una validazione di un campo:

<a4j:status>
    <f:facet name="start">
        <h:graphicImage value="/images/ai.gif" alt="ai"/>
    </f:facet>
</a4j:status>

Aggiungendo un tag come questo all’interno di una form nel caso di una chiamata ajax sarà automaticamente mostrato il contenuto del facet start, alla fine della chiamata sarà automaticamente nascosto.

jQuery BlockUI

L’esempio visto è molto semplice, ma come possiamo fare se vogliamo mettere una “schermatura” sulla pagina in modo da evitare altri input? Possiamo utilizzare jQuery BlockUI, un ottimo plugin di jQuery che ci permette di “bloccare” la nostra pagina. Vediamo come integrare questa libreria dentro una pagina RichFaces, partendo da una pagina molto semplice con una form:

<html xmlns="http://www.w3.org/1999/xhtml"
 xmlns:h="http://java.sun.com/jsf/html"
 xmlns:f="http://java.sun.com/jsf/core"
 xmlns:ui="http://java.sun.com/jsf/facelets"
 xmlns:a4j="http://richfaces.org/a4j"
 xmlns:rich="http://richfaces.org/rich">
<f:view>
<h:head><title>a4j status</title></h:head>
<h:body>
<rich:panel header="a4j status">
    <h:form>
        <h:panelGrid columns="2">
            <h:outputText value="UserName" />
            <h:inputText />
            <h:outputText value="Password" />
            <h:inputText />
        </h:panelGrid>
        <a4j:commandButton value="Check password"
            action="#{loginBean.check()}" />
        <a4j:commandButton value="Login" 
            action="#{loginBean.login()}" />
    </h:form>
</rich:panel>
</h:body>
</f:view>
</html>

Il risultato finale è questo:

jQuery BlockUI è, come molti plugin di jQuery, molto semplice da usare: eseguendo $.blockUI() viene eseguita una schermatura della pagina, chiamando $.unblockUI() la schermatura viene tolta. Come possiamo fare a usarlo con un a4j:status? Basta sfruttare gli attributi onstart, onsuccess e onerror che contengono codice JavaScript invocato automaticamente in corrispondenza di una chiamata ajax. Il tag risultante da aggiungere dentro la form è il seguente:

<a4j:status onstart="$.blockUI();"
    onerror="$.unblockUI();"
    onsuccess="$.unblockUI();" />

Per poter utilizzare il plugin dobbiamo anche includere il codice JavaScript nella pagina: il modo più semplice per aggiungerlo è includere questo tag script dopo l’apertura del tag h:body:

<script type="text/javascript"
    src="http://malsup.github.com/jquery.blockUI.js" />

Il risultato è questo, cliccando un button parte la chiamata a jQuery BlockUI che scherma l’intera pagina:

Indicatore di caricamento su un div

La a dell’acronimo ajax sta per asynchronous, bloccare tutta la pagina durante una chiamata può sembrare un controsenso! Vediamo quindi come bloccare solo una parte della pagina, per esempio un div che contiene alcuni campi. Per questo jQuery BlockUI ci viene in aiuto mettendo a disposizione il metodo block richiamabile su qualunque oggetto jQuery. Il modo più semplice di sfruttare questo metodo è creare un div (ovvero un h:panelGroup con layout="block") con una classe css (per esempio inputGrid) e richiamare il metodo JavaScript $('.inputGrid').block().

Usare una classe css per identificare un div può sembrare strano, la soluzione più naturale in questi casi è usare l’id del div per identificarlo. Però usando RichFaces l’id dei tag html risultanti sono calcolati dal framework, è necessario usare la function rich:clientId in un expression language per ottenerlo. Per semplificare il codice decidiamo di aggiungere una classe css usata come marker che non ha nessuno stile associato:

<h:form>
	<a4j:status onstart="$.blockUI();"
		onerror="$.unblockUI();" onsuccess="$.unblockUI();" />
	<a4j:status onstart="$('.inputGrid').block({ 
			message: 'Processing...', 
			css: { border: '3px solid #F00' },
			overlayCSS: { backgroundColor: '#00f' }
		});"
		name="passwordStatus"
		onerror="$('.inputGrid').unblock();" 
		onsuccess="$('.inputGrid').unblock();" />

	<h:panelGroup layout="block" styleClass="inputGrid">
		<h:panelGrid columns="2">
			<h:outputText value="UserName" />
			<h:inputText />
			<h:outputText value="Password" />
			<h:inputText />
		</h:panelGrid>
		<a4j:commandButton value="Check password" 
			action="#{loginBean.check()}"
			status="passwordStatus" />
		<a4j:commandButton value="Login" 
			action="#{loginBean.login()}" />
	</h:panelGroup>
</h:form>

In questa pagina ci sono due a4j:status, il secondo contiene l’attributo name che ci permette di identificarlo. Infatti nel primo commandButton è presente l’attributo status che indica quale status usare. Il secondo commandButton non avendo questo attributo utilizza lo status di default della form (ovvero quello senza attributo name).

Avendo sfruttato anche un po’ di attributi per cambiare lo stile del plugin otteniamo il seguente risultato (ok, potevamo sfruttare meglio questi attributi viste le scelte dei colori.. :)):

Conclusioni

Finisce qui questo post, il plugin di jQuery visto può rivelarsi molto utile. Se non avete ancora letto il nostro tutorial JavaScript e siete allergici al JavaScript potete includerlo dentro un custom tag facelet.

I plugin di jQuery sono veramente tanti, il sito ufficiale è in ristrutturazione ma cercando su Google se ne possono trovare facilmente molti. Se ne conoscete qualcuno che può essere utile in una rich internet application con RichFaces 4 fatecelo sapere nei commenti!

Libri consigliati

Fabio Collini

Software Architect con esperienza su piattaforma J2EE e attualmente focalizzato principalmente in progetti di sviluppo di applicazioni Android. Attualmente sono nel team Android di Cynny, ci stiamo occupando dello sviluppo dell'app Morphcast. Coautore della seconda edizione di Android Programmazione Avanzata e docente di corsi di sviluppo su piattaforma Android. Follow me on Twitter - LinkedIn profile - Google+