tete du loic

 Loïc YON [KIUX]

  • Enseignant-chercheur
  • Référent Formation Continue
  • Responsable des contrats pros ingénieur
  • Référent entrepreneuriat
  • Responsable de la filière F2 ingénieur
  • Secouriste Sauveteur du Travail
mail
loic.yon@isima.fr
phone
(+33 / 0) 4 73 40 50 42
location_on
ISIMA
  • twitter
  • linkedin
  • viadeo

[JEE] JSF & AJAX (2)

Date de première publication : 2012/06/06

Objectif et contexte

L'objectif de ce tutoriel est d'approfondir l'utilisation d'AJAX sur l'exercice du carnet d'adresse.

Nous allons réagir au survol d'une image et pour que ce soit plus joli, on va utiliser la bibliothèque jQuery.

Mise en place de la page

Nous reprenons les éléments précédents et nous affichons tout cela dans une page HTML

<h:dataTable value="#{carnetBean.getPersonnes()}" var="p" 
             rowClasses="line1,line0"
             styleClass="general"
             headerClass="header">
   <h:column><f:facet name="header">Nom</f:facet>#{p.getNom()}</h:column>
   <h:column><f:facet name="header">Prénom</f:facet>#{p.getPrenom()}</h:column>
   <h:column>
      <f:facet name="header">Lien</f:facet>
      <h:commandLink>
         <h:graphicImage library="images"  class="loupe" name="zoom.png" alt="zoom"/>
      </h:commandLink>
   </h:column>
</h:dataTable>  

Notons que sans AJAX, il aurait fallu spécifier un attribut action pour commandLink.

Il ne faut pas oublier la zone qui sera mise à jour par AJAX et qui affichera les données précises de la personne (attribut aafficher du bean managécarnetBean

<h:panelGroup id="ajaxcontent" layout="block" >
   #{carnetBean.aafficher.getPrenom()} #{carnetBean.aafficher.getNom()}<br />
   #{carnetBean.aafficher.getTel()}<br />
   #{carnetBean.aafficher.getMail()} <br />
   #{carnetBean.aafficher.getNote()}
</h:panelGroup>

Pour que ce soit plus joli, j'ajoute un gif animé pour faire patienter en début de body :

gif animé pour l'attente

<h:graphicImage library="images" name="ajax-loader.gif" id="wait" />

On cache l'image et la zone d'information avec jQuery. Pour insérer la bibliothèque :

<h:outputScript library="js" name="jquery.js" />

et le script à exécuter une fois que la page est chargée :

<script type="text/javascript">
    $(document).ready(function() {
        $('#ajaxcontent').hide();
        $('#wait').hide();
    });
</script>

La deuxième pincée d'AJAX

Nous ajoutons la balise <:ajax> à <commandLink> pour faire de l'AJAX.

<h:commandLink>
    <h:graphicImage library="images"  class="loupe" name="zoom.png" alt="zoom"/>
    <f:ajax  event="mouseover" render=":ajaxcontent" listener="#{carnetBean.update(p)}" onevent="essai" />
</h:commandLink>

Avec l'attribut event, on précise que l'événement qui nous intéresse n'est pas l'événement par défaut (le clic) mais bien le survol par la souris.

Avec l'attribut render, on précise la partie du code JSF qui sera mise à jour

Avec l'attribut listener, on précise ce que l'on veut faire lors de l'appel AJAX. En général, le listener est une méthode sans retour avec un paramètre implicite du type AjaxBehaviorEvent, mais on peut mettre également ce que l'on veut ;-) C'est cette option que j'ai retenue.

public void update(Personne p) {
  try {
    Thread.sleep(1000L);
  } catch (InterruptedException ex) {
    Logger.getLogger(CarnetBean.class.getName()).log(Level.SEVERE, null, ex);
  }
  aafficher = p;

Cette méthode précise la personne qui doit être affichée dans la zone de mise à jour AJAX par JSF. J'ai ajouté un délai pour simuler une opération un peu longuette.

Pour information, l'autre méthode pour passer des paramètres à un listener est d'utiliser la balise <f:param>. Pour les lire, on utilise le contexte Faces :

String p = FacesContext.getCurrentInstance().getExternalContext()
           .getRequestParameterMap().get("parametre");

Les paramètres sont passés au niveau de la requête et ne peuvent être que de type String.

Revenons à la description des paramètres de la balise <f:ajax>, il reste onevent. Ce paramètre permet de préciser la méthode JAVASCRIPT qui permet de gérer le cycle de vie des appels AJAX. En particulier, on peut appliquer des traitements suivant la progression de la requête : begin, complete, success. On peut également connaître le composant qui a initié la demande AJAX : source.

function essai(data) {
    if (data.status == "success") { 
        $('#ajaxcontent').offset({top: $(data.source).offset().top-20});
        $('#ajaxcontent').offset({left: $(data.source).offset().left+20});
    	$("#wait").hide();
        $('#ajaxcontent').show();
    	$("body").css('background-color','white');
        $(".loupe").mouseout(function(){
            $('#ajaxcontent').hide();
            $('#wait').hide();
        })
    } else {
        var w = $("#wait");
        w.css('margin-top', $(document).height()/2-w.height()/2);
        w.css('margin-left', $(document).width()/2-w.width()/2);
        w.show();
        $('#ajaxcontent').hide();
        $("body").css('background-color','lightgrey');
    }
}

Pour la gestion des erreurs, l'attribut onerror est disponible.

Beaucoup de choses dans cette méthode sont faites pour être esthétiques, en particulier la gestion de l'attente si la requête est longue. A vous d'adapter si cela ne vous plaît pas !

That's all folk !

Enfin, c'est mieux si je n'oublie pas les informations de style :

h2 {
    text-align: center;
}
            
.general {
    border:1px solid blue;
    border-collapse: collapse;
	margin : auto;
}
            
.header {
    color : white;
    background-color : blue;
    padding:0 10px 0 10px;
}
            
.line0 {
    background-color:white;
}

.line1 {
    background-color: #ccccff;
}
            
.line0 > td, .line1 > td {
    padding : 0 10px 0 10px;    
}

td+td+td {
    text-align : center;
}
            
#wait {
    display  : none;
    position : absolute;
    border-radius : 20px;
    border : grey solid 2px;
    padding : 10px;
    background-color:white;
}
            
#ajaxcontent {
    border:2px dashed orange;
    background-color : yellow;
    width : 300px;
    border-radius:20px;
    padding:5px 10px 5px 20px;
    position:absolute;
    top : 60px;
    left:200px;
}