Vous êtes sur la page 1sur 21

Tutoriel sur la cration d'un composant JSF CP/Ville

Par Franck Gasparotto

Date de publication : 3 juillet 2015

Cet article prsente une mthodologie pour crer un composant JSF de deux manires
diffrentes.
Pour ragir au contenu de cet article, un espace de dialogue vous est propos sur le forum.
Commentez

Tutoriel sur la cration d'un composant JSF CP/Ville par Franck Gasparotto

I - Introduction..............................................................................................................................................................3
II - Prsentation du composant................................................................................................................................... 3
III - Prparation............................................................................................................................................................ 6
IV - Mthode 1 : Composant facelet par inclusion....................................................................................................11
V - Mthode 2 : Composant facelet composite.........................................................................................................16
VI - Conclusion.......................................................................................................................................................... 21
VII - Remerciements.................................................................................................................................................. 21

-2-

Copyright 2015 Franck Gasparotto. Aucune reproduction, mme partielle, ne peut tre faite de ce site et de l'ensemble de son contenu : textes, documents,
images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu' trois ans de prison et jusqu' 300 000 de dommages et intrts.
http://keeleek.developpez.com/tutoriels/jsf/methodologie-creation-composant-richfaces-cp-ville/

Tutoriel sur la cration d'un composant JSF CP/Ville par Franck Gasparotto

I - Introduction
Nous allons aborder les concepts de rutilisabilit en JSF en crant un composant CP (Code Postal)/Ville avec
Richfaces 4.5 de deux manires diffrentes :
1
2

Via le principe d'include de facelet ;


En crant un composant composite, plus connu sous son terme anglais composite component.

II - Prsentation du composant
Le composant CP/Ville permet de trouver une ville en tapant son code postal. Si plusieurs villes correspondent
la saisie du code postal, une liste droulante permet de choisir la ville. Dans le cas contraire, le champ ville est
automatiquement rempli avec l'unique ville correspondante. La vido ci-aprs montre son utilisation :

Cliquer sur ce lien pour lancer l'animation

Au niveau du modle de donnes :

une ville ne peut avoir qu'un code postal cependant un code postal peut-tre associ plusieurs villes ;
la correspondance entre les villes et les codes postaux se fait via une table code_postal dont voici la structure

Voici un chantillon de donnes :

Dans le code source du fieldset Adresse Pro , le futur composant est le panelGroup #pro et sa reprsentation
selon le modle des botes est la suivante :

-3-

Copyright 2015 Franck Gasparotto. Aucune reproduction, mme partielle, ne peut tre faite de ce site et de l'ensemble de son contenu : textes, documents,
images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu' trois ans de prison et jusqu' 300 000 de dommages et intrts.
http://keeleek.developpez.com/tutoriels/jsf/methodologie-creation-composant-richfaces-cp-ville/

Tutoriel sur la cration d'un composant JSF CP/Ville par Franck Gasparotto

1. <fieldset style="max-width:600px">
2.
<legend>Adresse Pro</legend>
3.
<h:panelGrid columns="2" >
4.
5.
<h:outputLabel value="Adresse " for="pro_adresse" />
6.
<h:inputText id="pro_adresse" value="#{exempleCpVilleBean.proAdresse}"
7.
style="width: 262px"
8.
onchange="notifyChange()"
9.
tabindex="1" />
10.
11.
<h:panelGroup>
12.
<h:outputLabel value="CP " for="pro_cp" />/
13.
<h:outputLabel value=" Ville" for="pro_ville" />
14.
</h:panelGroup>
15.
16.
<h:panelGroup id="pro" layout="block" styleClass="middle">
17.
<a4j:jsFunction id="fCp_pro" name="searchCp_pro" immediate="true" render="pro_pgVille" limitRender="true"
18.
oncomplete="keeUtils.goToNextTabIndex( #{rich:element('pro_cp')} );">
19.
<a4j:param name="param1" assignTo="#{exempleCpVilleBean.proCp}" />
20.
<f:setPropertyActionListener value="#{exempleCpVilleBean.proCp}" target="#{cpVilleBean.cp}" />
21.
<f:setPropertyActionListener value="#{cpVilleBean.ville}" target="#{exempleCpVilleBean.proVille}" />
22.
</a4j:jsFunction>
23.
24.
<h:panelGroup layout="block" style="display:inline-block" styleClass="middle">
25.
<h:inputText id="pro_cp" value="#{exempleCpVilleBean.proCp}"
26.
maxlength="5"
27.
style="width:55px;margin:0px;"
28.
styleClass="smoothReadonly middle"
29.
required="true" label="Cp Pro"
30.
onkeyup="if ($(event).which !
= 16) { if (keeUtils.cpOK(this.value)) { searchCp_pro(this.value); }}"
31.
onchange="notifyChange()"
32.
tabindex="2" >
33.
</h:inputText>
34.
</h:panelGroup>
35.
<h:panelGroup layout="block" id="pro_pgVille" style="display:inlineblock;margin:0px 0px 0px 3px" styleClass="middle" >
36.
<h:inputText id="pro_ville" value="#{exempleCpVilleBean.proVille}"
37.
style="width:200px;margin:0px;"
38.
styleClass="smoothReadonly"
39.
rendered="#{not empty exempleCpVilleBean.proVille or empty cpVilleBean.villes or empty
40.
onchange="notifyChange()"
41.
required="true" label="Ville pro"
42.
tabindex="3" />
43.
44.
<rich:autocomplete id="pro_villes" value="#{exempleCpVilleBean.proVille}"
45.
inputClass="pro_comboVille"
46.
styleClass="middle"
47.
rendered="#{not empty cpVilleBean.villes and empty exempleCpVilleBean.proVille and (fn
48.
onchange="notifyChange()"
49.
required="true" label="Ville pro"
50.
tabindex="3"
51.
mode="client" showButton="true" selectFirst="true" autofill="true" layout="div"
52.
autocompleteList="#{cpVilleBean.villes}" var="vil" fetchValue="#{vil.value}" >
-4-

Copyright 2015 Franck Gasparotto. Aucune reproduction, mme partielle, ne peut tre faite de ce site et de l'ensemble de son contenu : textes, documents,
images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu' trois ans de prison et jusqu' 300 000 de dommages et intrts.
http://keeleek.developpez.com/tutoriels/jsf/methodologie-creation-composant-richfaces-cp-ville/

Tutoriel sur la cration d'un composant JSF CP/Ville par Franck Gasparotto

53.
#{vil.label}
54.
</rich:autocomplete>
55.
</h:panelGroup>
56.
</h:panelGroup>
57.
</h:panelGrid>
58. </fieldset>

Ct Java, je ne vais pas entrer dans les dtails. J'utilise le bean manag CpVilleBean qui s'occupe de rechercher
la/les ville/s associe/s au CP saisi et qui construit une liste de selectItem pour alimenter le combo dans le cas o
il y a plusieurs villes.
Extrait de CpVilleBean.java

1. /**
2. * Bean utilis pour renseigner le champ ville du composant cpVille
3. *
4. * @author keeleek
5. * @category backed
6. */
7. public class CpVilleBean implements ConversationBindingListener {
8.
9.
private static Log log = LogFactory.getLog(CpVilleBean.class);
10.
/**
11.
* champs cp
12.
*
13.
* @category jsf
14.
*/
15.
private String cp;
16.
/**
17.
* liste des villes pour le combo
18.
*
19.
* @category jsf
20.
*/
21.
private final List<SelectItem> villes = new ArrayList<SelectItem>();
22.
/**
23.
* champs ville
24.
*
25.
* @category jsf
26.
*/
27.
private String ville;
28.
29.
/**
30.
* id ville slectionne
31.
*
32.
* @category jsf
33.
*/
34.
private Integer idVille;
35.
/**
36.
*
37.
* @category dao
38.
*/
39.
private ScaCodePostalDAO scaCodePostalDAO;
40.
41.
public CpVilleBean() {
42.
}
43.
44.
/**
45.
* getCp
46.
*
47.
* @return cp
48.
*/
49.
public String getCp() {
50.
return cp;
51.
}
52.
53.
/**
54.
* setCp
55.
*
56.
* @param cp
57.
*/
58.
public void setCp(String cp) {
-5-

Copyright 2015 Franck Gasparotto. Aucune reproduction, mme partielle, ne peut tre faite de ce site et de l'ensemble de son contenu : textes, documents,
images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu' trois ans de prison et jusqu' 300 000 de dommages et intrts.
http://keeleek.developpez.com/tutoriels/jsf/methodologie-creation-composant-richfaces-cp-ville/

Tutoriel sur la cration d'un composant JSF CP/Ville par Franck Gasparotto

Extrait de CpVilleBean.java
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
}
85. ...

List<ScaCodePostal> codes;
if (this.cp != null && this.cp.equals(cp)) {
return;
}
this.cp = cp;
villes.clear();
ville = "";
if (this.cp == null || this.cp.length() != 5) {
return;
}
codes = scaCodePostalDAO.getByCp(cp);
if (codes.isEmpty()) {
return;
}
if (codes.size() == 1) {
ville = codes.get(0).getVille();
}
else {
for (ScaCodePostal code : codes) {
villes.add(new SelectItem(code.getVille()));
}
}

Maintenant que je vous ai prsent les fonctionnalits du composant et sa structure, le but est de factoriser ce code
afin de pouvoir le rutiliser simplement sans avoir faire un copier/coller.

III - Prparation
Avant factorisation, le code de la vido d'exemple ressemble ceci :
Avant factorisation

1. <h:outputScript library="default" name="js/utils.js" target="head" />


2. <h:outputStylesheet>
3.
input.pro_comboVille { width: 186px; }
4.
input.perso_comboVille { width: 224px }
5.
.middle { vertical-align: middle }
6. </h:outputStylesheet>
7.
8. <h:form id="fCpVil">
9.
<rich:panel>
10.
<f:facet name="header">Composant CP/Ville</f:facet>
11.
12.
<h:panelGroup layout="block">
13.
<fieldset style="max-width:600px">
14.
<legend>Adresse Pro</legend>
15.
<h:panelGrid columns="2" >
16.
17.
<h:outputLabel value="Adresse " for="pro_adresse" />
18.
<h:inputText id="pro_adresse" value="#{exempleCpVilleBean.proAdresse}"
19.
style="width: 262px"
20.
onchange="notifyChange()"
21.
tabindex="1" />
22.
23.
<h:panelGroup>
24.
<h:outputLabel value="CP " for="pro_cp" />/
25.
<h:outputLabel value=" Ville" for="pro_ville" />
26.
</h:panelGroup>
27.
28.
<h:panelGroup id="pro" layout="block" styleClass="middle">
29.
<a4j:jsFunction id="fCp_pro" name="searchCp_pro" immediate="true" render="pro_pgVille" limitRender="true"
30.
oncomplete="keeUtils.goToNextTabIndex( #{rich:element('pro_cp')} );">
-6-

Copyright 2015 Franck Gasparotto. Aucune reproduction, mme partielle, ne peut tre faite de ce site et de l'ensemble de son contenu : textes, documents,
images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu' trois ans de prison et jusqu' 300 000 de dommages et intrts.
http://keeleek.developpez.com/tutoriels/jsf/methodologie-creation-composant-richfaces-cp-ville/

Tutoriel sur la cration d'un composant JSF CP/Ville par Franck Gasparotto

Avant factorisation

31.
<a4j:param name="param1" assignTo="#{exempleCpVilleBean.proCp}" />
32.
<f:setPropertyActionListener value="#{exempleCpVilleBean.proCp}" target="#{cpVilleBean.cp}" />
33.
<f:setPropertyActionListener value="#{cpVilleBean.ville}" target="#{exempleCpVilleBean.proVille}" />
34.
</a4j:jsFunction>
35.
36.
<h:panelGroup layout="block" style="display:inline-block" styleClass="middle">
37.
<h:inputText id="pro_cp" value="#{exempleCpVilleBean.proCp}"
38.
maxlength="5"
39.
style="width:55px;margin:0px;"
40.
styleClass="smoothReadonly middle"
41.
required="true" label="Cp Pro"
42.
onkeyup="if ($(event).which !
= 16) { if (keeUtils.cpOK(this.value)) { searchCp_pro(this.value); }}"
43.
onchange="notifyChange()"
44.
tabindex="2" >
45.
</h:inputText>
46.
</h:panelGroup>
47.
<h:panelGroup layout="block" id="pro_pgVille" style="display:inlineblock;margin:0px 0px 0px 3px" styleClass="middle" >
48.
<h:inputText id="pro_ville" value="#{exempleCpVilleBean.proVille}"
49.
style="width:200px;margin:0px;"
50.
styleClass="smoothReadonly"
51.
rendered="#{not empty exempleCpVilleBean.proVille or empty cpVilleBean.villes
52.
onchange="notifyChange()"
53.
required="true" label="Ville pro"
54.
tabindex="3" />
55.
56.
<rich:autocomplete id="pro_villes" value="#{exempleCpVilleBean.proVille}"
57.
inputClass="pro_comboVille"
58.
styleClass="middle"
59.
rendered="#{not empty cpVilleBean.villes and empty exempleCpVilleBean.proVille
60.
onchange="notifyChange()"
61.
required="true" label="Ville pro"
62.
tabindex="3"
63.
mode="client" showButton="true" selectFirst="true" autofill="true" layout="div
64.
autocompleteList="#{cpVilleBean.villes}" var="vil" fetchValue="#{vil.value}" >
65.
#{vil.label}
66.
</rich:autocomplete>
67.
</h:panelGroup>
68.
</h:panelGroup>
69.
</h:panelGrid>
70.
</fieldset>
71.
</h:panelGroup>
72.
<h:panelGroup layout="block">
73.
<fieldset style="max-width:600px">
74.
<legend>Adresse Perso</legend>
75.
<h:panelGrid columns="2" >
76.
77.
<h:outputLabel value="Adresse " for="perso_adresse" />
78.
<h:inputText id="perso_adresse" value="#{exempleCpVilleBean.persoAdresse}"
79.
style="width: 300px"
80.
onchange="notifyChange()"
81.
tabindex="4" />
82.
83.
<h:panelGroup>
84.
<h:outputLabel value="CP " for="perso_cp" />/
85.
<h:outputLabel value=" Ville" for="perso_ville" />
86.
</h:panelGroup>
87.
88.
<h:panelGroup id="perso" layout="block" styleClass="middle">
89.
<a4j:jsFunction id="fCp_perso" name="searchCp_perso" immediate="true" render="perso_pgVille" limitRender="true"
90.
oncomplete="keeUtils.goToNextTabIndex( #{rich:element('perso_cp')} );">
91.
<a4j:param name="param1" assignTo="#{exempleCpVilleBean.persoCp}" />
92.
<f:setPropertyActionListener value="#{exempleCpVilleBean.persoCp}" target="#{cpVilleBean.cp}" />
93.
<f:setPropertyActionListener value="#{cpVilleBean.ville}" target="#{exempleCpVilleBean.persoVille}" />
-7-

Copyright 2015 Franck Gasparotto. Aucune reproduction, mme partielle, ne peut tre faite de ce site et de l'ensemble de son contenu : textes, documents,
images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu' trois ans de prison et jusqu' 300 000 de dommages et intrts.
http://keeleek.developpez.com/tutoriels/jsf/methodologie-creation-composant-richfaces-cp-ville/

Tutoriel sur la cration d'un composant JSF CP/Ville par Franck Gasparotto

Avant factorisation

94.
</a4j:jsFunction>
95.
96.
<h:panelGroup layout="block" style="display:inline-block" styleClass="middle">
97.
<h:inputText id="perso_cp" value="#{exempleCpVilleBean.persoCp}"
98.
maxlength="5"
99.
style="width:55px;margin:0px;"
100.
styleClass="smoothReadonly middle"
101.
required="true" label="Cp perso"
102.
onkeyup="if ($(event).which !
= 16) { if (keeUtils.cpOK(this.value)) { searchCp_perso(this.value); }}"
103.
onchange="notifyChange()"
104.
tabindex="5" >
105.
</h:inputText>
106.
</h:panelGroup>
107.
<h:panelGroup layout="block" id="perso_pgVille" style="display:inlineblock;margin:0px 0px 0px 3px" styleClass="middle" >
108.
<h:inputText id="perso_ville" value="#{exempleCpVilleBean.persoVille}"
109.
style="width:238px;margin:0px;"
110.
styleClass="smoothReadonly"
111.
rendered="#{not empty exempleCpVilleBean.persoVille or empty cpVilleBean.vill
112.
onchange="notifyChange()"
113.
required="true" label="Ville perso"
114.
tabindex="6" />
115.
116.
<rich:autocomplete id="perso_villes" value="#{exempleCpVilleBean.persoVille}"
117.
inputClass="perso_comboVille"
118.
styleClass="middle"
119.
rendered="#{not empty cpVilleBean.villes and empty exempleCpVilleBean.persoVi
120.
onchange="notifyChange()"
121.
required="true" label="Ville perso"
122.
tabindex="6"
123.
mode="client" showButton="true" selectFirst="true" autofill="true" layout="di
124.
autocompleteList="#{cpVilleBean.villes}" var="vil" fetchValue="#{vil.value}"
125.
#{vil.label}
126.
</rich:autocomplete>
127.
</h:panelGroup>
128.
</h:panelGroup>
129.
</h:panelGrid>
130.
</fieldset>
131.
</h:panelGroup>
132.
<a4j:commandButton id="savBtn" value="Save" disabled="#{not exempleCpVilleBean.saveBtnOn}"
133.
execute="@form"
134.
action="#{exempleCpVilleBean.save}"
135.
render="savBtn"
136.
style="margin-top:10px" />
137.
</rich:panel>
138.
<a4j:jsFunction id="js1" name="notifyChange"
139.
execute="@this"
140.
render="savBtn"
141.
limitRender="true">
142.
<f:setPropertyActionListener value="true" target="#{exempleCpVilleBean.saveBtnOn}" />
143.
</a4j:jsFunction>
144. </h:form>

Aprs factorisation, suivant les deux mthodes que je vais vous prsenter, nous obtiendrons :
Aprs factorisation

1. <h:outputStylesheet>
2.
input.pro.comboVille { width: 186px; }
3.
input.perso.comboVille {width: 224px}
4. </h:outputStylesheet>
5. <h:form id="fCpVil">
6.
<rich:panel>
7.
<f:facet name="header">Composant CP/Ville</f:facet>
8.
9.
<h:panelGroup layout="block">
10.
<fieldset style="max-width:600px">
-8-

Copyright 2015 Franck Gasparotto. Aucune reproduction, mme partielle, ne peut tre faite de ce site et de l'ensemble de son contenu : textes, documents,
images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu' trois ans de prison et jusqu' 300 000 de dommages et intrts.
http://keeleek.developpez.com/tutoriels/jsf/methodologie-creation-composant-richfaces-cp-ville/

Tutoriel sur la cration d'un composant JSF CP/Ville par Franck Gasparotto

Aprs factorisation

11.
<legend>Adresse Pro</legend>
12.
<h:panelGrid columns="2" >
13.
14.
<h:outputLabel value="Adresse " for="pro_adresse" />
15.
<h:inputText id="pro_adresse" value="#{exempleCpVilleBean.proAdresse}"
16.
style="width: 262px"
17.
onchange="notifyChange()"
18.
tabindex="1" />
19.
20.
<h:panelGroup>
21.
<h:outputLabel value="CP " for="pro_cp" />/
22.
<h:outputLabel value=" Ville" for="pro_ville" />
23.
</h:panelGroup>
24.
25.
<ui:include src="/composant/cpVille.xhtml">
26.
<ui:param name="id" value="pro" />
27.
<ui:param name="cp" value="#{exempleCpVilleBean.proCp}" />
28.
<ui:param name="ville" value="#{exempleCpVilleBean.proVille}" />
29.
<ui:param name="required" value="true" />
30.
<ui:param name="villeWidth" value="200px" />
31.
<ui:param name="styleClass" value="pro" />
32.
<ui:param name="onchange" value="notifyChange()" />
33.
</ui:include>
34.
</h:panelGrid>
35.
</fieldset>
36.
</h:panelGroup>
37.
<h:panelGroup layout="block">
38.
<fieldset style="max-width:600px">
39.
<legend>Adresse Perso</legend>
40.
<h:panelGrid columns="2" >
41.
42.
<h:outputLabel value="Adresse " for="perso_adresse" />
43.
<h:inputText id="perso_adresse" value="#{exempleCpVilleBean.persoAdresse}"
44.
style="width: 300px"
45.
onchange="notifyChange()"
46.
tabindex="4" />
47.
48.
<h:panelGroup>
49.
<h:outputLabel value="CP " for="perso_cp" />/
50.
<h:outputLabel value=" Ville" for="perso_ville" />
51.
</h:panelGroup>
52.
53.
<kee:cpVille id="perso"
54.
cp="#{exempleCpVilleBean.persoCp}"
55.
ville="#{exempleCpVilleBean.persoVille}"
56.
required="true"
57.
villeWidth="238px"
58.
styleClass="perso"
59.
tabindex="5"
60.
onchange="notifyChange()" />
61.
</h:panelGrid>
62.
</fieldset>
63.
</h:panelGroup>
64.
<a4j:commandButton id="savBtn" value="Save" disabled="#{not exempleCpVilleBean.saveBtnOn}"
65.
execute="@form"
66.
action="#{exempleCpVilleBean.save}"
67.
render="savBtn"
68.
style="margin-top:10px" />
69.
</rich:panel>
70.
<a4j:jsFunction id="js1" name="notifyChange"
71.
execute="@this"
72.
render="savBtn"
73.
limitRender="true">
74.
<f:setPropertyActionListener value="true" target="#{exempleCpVilleBean.saveBtnOn}" />
75.
</a4j:jsFunction>
76. </h:form>

Voici un comparatif visuel avant/aprs :

-9-

Copyright 2015 Franck Gasparotto. Aucune reproduction, mme partielle, ne peut tre faite de ce site et de l'ensemble de son contenu : textes, documents,
images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu' trois ans de prison et jusqu' 300 000 de dommages et intrts.
http://keeleek.developpez.com/tutoriels/jsf/methodologie-creation-composant-richfaces-cp-ville/

Tutoriel sur la cration d'un composant JSF CP/Ville par Franck Gasparotto

Bloc adresse pro

Bloc adresse perso


Certains lments vont devenir des paramtres suite la factorisation du code de notre futur composant. Ainsi
la premire tape dans la cration d'un composant consiste identifier ses paramtres. Comment ? En faisant
exactement ce que nous voulons viter de faire : un copier/coller. Nous allons donc :
1
2
3
4

Dupliquer les lments du composant dans la mme page via un copier/coller du code ;
Le rendre fonctionnel en modifiant un minimum de code ;
Comparer les lments qui diffrent ;
Identifier le code spcifique au scnario de la page courante.

Aprs avoir test que les deux composants fonctionnent bien dans une mme page, je les ai isols dans deux fichiers
diffrents et les ai compars (en utilisant la fonction compare with each other d'Eclipse par exemple).

- 10 -

Copyright 2015 Franck Gasparotto. Aucune reproduction, mme partielle, ne peut tre faite de ce site et de l'ensemble de son contenu : textes, documents,
images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu' trois ans de prison et jusqu' 300 000 de dommages et intrts.
http://keeleek.developpez.com/tutoriels/jsf/methodologie-creation-composant-richfaces-cp-ville/

Tutoriel sur la cration d'un composant JSF CP/Ville par Franck Gasparotto

Les lments qui diffrent sont donc :

la proprit cp du bean, valeur du champ de saisie du cp ;


la proprit ville du bean, valeur du champ de saisie de ville ;
les id ;
le nom de la fonction de recherche par CP ;
les labels des champs de saisie ;
les tabindex ;
la taille de l'input text ville ;
la classe du combo ville (qui permet d'agir sur sa taille) ;
la fonction notifyChange dans l'vnement onchange : elle permet de dgriser le bouton Enregistrer suite
une modification de la valeur du champ, elle est donc spcifique au scnario de la page courante.

Nous pouvons passer l'tape suivante : la cration du composant selon la 1

re

mthode.

IV - Mthode 1 : Composant facelet par inclusion


La premire mthode de cration du composant consiste externaliser le code dans une facelet, un fichier part
que je nomme cpVille.xhtml et que je place de manire arbitraire dans le dossier WebContent/composant/
/WebContent/composant/cpVille.xhtml

1. <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/


xhtml1-transitional.dtd">
2. <html xmlns="http://www.w3.org/1999/xhtml"
3.
xmlns:ui="http://java.sun.com/jsf/facelets"
4.
xmlns:f="http://java.sun.com/jsf/core"
5.
xmlns:h="http://java.sun.com/jsf/html"
6.
xmlns:fn="http://java.sun.com/jsp/jstl/functions"
7.
xmlns:rich="http://richfaces.org/rich"
8.
xmlns:a4j="http://richfaces.org/a4j" >
9.
10. <ui:composition>
11.
<h:panelGroup id="pro" layout="block" styleClass="middle">
12.
<a4j:jsFunction id="fCp_pro" name="searchCp_pro" immediate="true" render="pro_pgVille" limitRender="true"
13.
oncomplete="keeUtils.goToNextTabIndex( #{rich:element('pro_cp')} );">
14.
<a4j:param name="param1" assignTo="#{exempleCpVilleBean.proCp}" />
15.
<f:setPropertyActionListener value="#{exempleCpVilleBean.proCp}" target="#{cpVilleBean.cp}" />
16.
<f:setPropertyActionListener value="#{cpVilleBean.ville}" target="#{exempleCpVilleBean.proVille}" />
17.
</a4j:jsFunction>
18.
19.
<h:panelGroup layout="block" style="display:inline-block" styleClass="middle">
20.
<h:inputText id="pro_cp" value="#{exempleCpVilleBean.proCp}"
21.
maxlength="5"
22.
style="width:55px;margin:0px;"

- 11 -

Copyright 2015 Franck Gasparotto. Aucune reproduction, mme partielle, ne peut tre faite de ce site et de l'ensemble de son contenu : textes, documents,
images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu' trois ans de prison et jusqu' 300 000 de dommages et intrts.
http://keeleek.developpez.com/tutoriels/jsf/methodologie-creation-composant-richfaces-cp-ville/

Tutoriel sur la cration d'un composant JSF CP/Ville par Franck Gasparotto

/WebContent/composant/cpVille.xhtml

23.
styleClass="smoothReadonly middle"
24.
required="true" label="Cp Pro"
25.
onkeyup="if ($(event).which !
= 16) { if (keeUtils.cpOK(this.value)) { searchCp_pro(this.value); }}"
26.
onchange="notifyChange()"
27.
tabindex="2" >
28.
</h:inputText>
29.
</h:panelGroup>
30.
<h:panelGroup layout="block" id="pro_pgVille" style="display:inlineblock;margin:0px 0px 0px 3px" styleClass="middle" >
31.
<h:inputText id="pro_ville" value="#{exempleCpVilleBean.proVille}"
32.
style="width:200px;margin:0px;"
33.
styleClass="smoothReadonly"
34.
rendered="#{not empty exempleCpVilleBean.proVille or empty cpVilleBean.villes or empty exe
35.
onchange="notifyChange()"
36.
required="true" label="Ville pro"
37.
tabindex="3" />
38.
39.
<rich:autocomplete id="pro_villes" value="#{exempleCpVilleBean.proVille}"
40.
inputClass="pro_comboVille"
41.
styleClass="middle"
42.
rendered="#{not empty cpVilleBean.villes and empty exempleCpVilleBean.proVille and (fn:len
43.
onchange="notifyChange()"
44.
required="true" label="Ville pro"
45.
tabindex="3"
46.
mode="client" showButton="true" selectFirst="true" autofill="true" layout="div"
47.
autocompleteList="#{cpVilleBean.villes}" var="vil" fetchValue="#{vil.value}" >
48.
#{vil.label}
49.
</rich:autocomplete>
50.
</h:panelGroup>
51.
</h:panelGroup>
52. </ui:composition>
53. </html>

La balise la plus importante est <ui:composition> qui encapsule le code du composant. Attention, tout ce qui est
l'extrieur de cette balise ne sera pas pris en compte !
Ds maintenant, <ui:include> me permet de remplacer les champs cp et ville dans mon formulaire exemple de la
manire suivante :
1. <fieldset style="max-width:600px">
2.
<legend>Adresse Pro</legend>
3.
<h:panelGrid columns="2" >
4.
5.
<h:outputLabel value="Adresse " for="pro_adresse" />
6.
<h:inputText id="pro_adresse" value="#{exempleCpVilleBean.proAdresse}"
7.
style="width: 262px"/>
8.
9.
<h:panelGroup>
10.
<h:outputLabel value="CP " for="pro_cp" />/
11.
<h:outputLabel value=" Ville" for="pro_ville" />
12.
</h:panelGroup>
13.
14.
<ui:include src="/composant/cpVille.xhtml" ></ui:include>
15.
</h:panelGrid>
16. </fieldset>

Ensuite, je n'ai plus qu' placer mes paramtres en utilisant des Expression Languages #{nom_param} ce qui
donne :
/WebContent/composant/cpVille.xhtml
1. <ui:composition>
2.
<h:panelGroup
3.
4.
<ui:param
5.
<ui:param
6.
<ui:param

id="#{id}" layout="block" styleClass="middle">


name="idCp" value="#{id}_cp" />
name="idVille" value="#{id}_ville" />
name="idVilles" value="#{id}_villes" />
- 12 -

Copyright 2015 Franck Gasparotto. Aucune reproduction, mme partielle, ne peut tre faite de ce site et de l'ensemble de son contenu : textes, documents,
images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu' trois ans de prison et jusqu' 300 000 de dommages et intrts.
http://keeleek.developpez.com/tutoriels/jsf/methodologie-creation-composant-richfaces-cp-ville/

Tutoriel sur la cration d'un composant JSF CP/Ville par Franck Gasparotto

/WebContent/composant/cpVille.xhtml
7.
8.
9.

<ui:param name="idGroupVille" value="#{id}_pgVille" />

<a4j:jsFunction id="fCp_#{id}" name="searchCp_#{id}" immediate="true" render="#{idGroupVille}" limitRender="true


10.
oncomplete="keeUtils.goToNextTabIndex( #{rich:element(idCp)} );">
11.
<a4j:param name="param1" assignTo="#{cp}" />
12.
<f:setPropertyActionListener value="#{cp}" target="#{cpVilleBean.cp}" />
13.
<f:setPropertyActionListener value="#{cpVilleBean.ville}" target="#{ville}" />
14.
</a4j:jsFunction>
15.
16.
<h:panelGroup layout="block" style="display:inline-block" styleClass="middle">
17.
<h:inputText id="#{idCp}" value="#{cp}"
18.
maxlength="5"
19.
style="width:55px;margin:0px;"
20.
styleClass="smoothReadonly middle"
21.
required="true" label="Cp #{label}"
22.
onkeyup="if ($(event).which !
= 16) { if (keeUtils.cpOK(this.value)) { searchCp_#{id}(this.value); }}"
23.
onchange="#{onchange}"
24.
tabindex="#{tabindex}" >
25.
</h:inputText>
26.
</h:panelGroup>
27.
<h:panelGroup layout="block" id="#{idGroupVille}" style="display:inlineblock;margin:0px 0px 0px 3px" styleClass="middle" >
28.
<h:inputText id="#{idVille}" value="#{ville}"
29.
style="width:#{villeWidth};margin:0px;"
30.
styleClass="smoothReadonly"
31.
rendered="#{not empty ville or empty cpVilleBean.villes or empty cp}"
32.
onchange="#{onchange}"
33.
required="true" label="Ville pro"
34.
tabindex="#{(tabindex==null)?'':(tabindex+1)}" />
35.
36.
<rich:autocomplete id="#{idVilles}" value="#{ville}"
37.
inputClass="#{styleClass}_comboVille"
38.
styleClass="middle"
39.
rendered="#{not empty cpVilleBean.villes and empty ville and (fn:length(cp)==5)}"
40.
onchange="#{onchange}"
41.
required="true" label="Ville #{label}"
42.
tabindex="#{(tabindex==null)?'':(tabindex+1)}"
43.
mode="client" showButton="true" selectFirst="true" autofill="true" layout="div"
44.
autocompleteList="#{cpVilleBean.villes}" var="vil" fetchValue="#{vil.value}" >
45.
#{vil.label}
46.
</rich:autocomplete>
47.
</h:panelGroup>
48.
</h:panelGroup>
49. </ui:composition>

Voici la liste des paramtres crs :

cp : la valeur du champ de saisie du cp ;


ville : la valeur du champ de saisie de la ville ;
id : au lieu de crer un paramtre id pour chaque champ, j'utilise un seul paramtre qui sert construire les
autres id en dclarant une variable dans la facelet (<ui:param>). Je peux rutiliser du coup ses variables
dans les attributs execute, render, oncomplete de ma fonction. id sert aussi construire le nom de la fonction
JavaScript qui doit tre unique pour chaque composant ;
label : ici aussi j'utilise un seul paramtre qui servira construire le label du champ cp et du champ ville
(affich en cas de champ vide) ;
tabindex : le tabindex du champ cp ;
villeWidth : permet de spcifier la longueur de l'input text ville
styleClass : permet de spcifier une classe qui s'appliquera au composant combo ;
onchange : fonction JavaScript qui sera excute lors du dclenchement de l'vnement onchange des
champs de saisie.

Pour les passer ma facelet, il faut utiliser <ui:param> au niveau de l'inclusion :

- 13 -

Copyright 2015 Franck Gasparotto. Aucune reproduction, mme partielle, ne peut tre faite de ce site et de l'ensemble de son contenu : textes, documents,
images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu' trois ans de prison et jusqu' 300 000 de dommages et intrts.
http://keeleek.developpez.com/tutoriels/jsf/methodologie-creation-composant-richfaces-cp-ville/

Tutoriel sur la cration d'un composant JSF CP/Ville par Franck Gasparotto

1. <ui:include src="/composant/cpVille.xhtml">
2.
<ui:param name="id" value="pro" />
3.
<ui:param name="cp" value="#{exempleCpVilleBean.proCp}" />
4.
<ui:param name="ville" value="#{exempleCpVilleBean.proVille}" />
5.
<ui:param name="villeWidth" value="200px" />
6.
<ui:param name="styleClass" value="pro" />
7.
<ui:param name="onchange" value="notifyChange()" />
8. </ui:include>

Notre composant possde dj l'essentiel pour tre rutilis dans d'autres crans, mais il ne permet pas de raliser
ce que la plupart des composants JSF de base permettent savoir :

paramtrer sa visibilit : rendered ;


changer son tat actif/inactif/lecture seule : disabled / readonly ;
rendre un champ obligatoire ou non : required.

De plus, comment faire pour ajouter un vnement onkeyup/onblur/onfocus sur l'un des inputs text ?
Vous l'avez compris, nous allons lui ajouter d'autres paramtres.
/WebContent/composant/cpVille.xhtml

1. <ui:composition>
2.
3.
<ui:param name="rendered" value="#{(rendered==null)?true:rendered}" />
4.
5.
<h:panelGroup id="#{id}" layout="block" rendered="#{rendered}" styleClass="clearFloat middle">
6.
7.
<h:outputStylesheet library="default" name="css/cpVille.css" />
8.
<h:outputScript library="default" name="js/utils.js" target="head" />
9.
10.
<ui:param name="idCp" value="#{id}_cp" />
11.
<ui:param name="idVille" value="#{id}_ville" />
12.
<ui:param name="idVilles" value="#{id}_villes" />
13.
<ui:param name="idGroupVille" value="#{id}_pgVille" />
14.
<ui:param name="label" value="#{(label==null)?'':label}" />
15.
<ui:param name="tabindexSup" value="#{(tabindex==null) ? '' : tabindex + 1}" />
16.
<ui:param name="readonly" value="#{(readonly==null)?false:readonly}" />
17.
<ui:param name="disabled" value="#{(disabled==null)?false:disabled}" />
18.
<ui:param name="required" value="#{(required==null)?false:required}" />
19.
<ui:param name="villeWidth" value="#{(villeWidth==null)?'170px':villeWidth}" />
20.
21.
<a4j:jsFunction id="fCp_#{id}" name="searchCp_#{id}" immediate="true" render="#{idGroupVille}" limitRender="true
22.
oncomplete="keeUtils.goToNextTabIndex( #{rich:element(idCp)} );">
23.
<a4j:param name="param1" assignTo="#{cp}" />
24.
<f:setPropertyActionListener value="#{cp}" target="#{cpVilleBean.cp}" />
25.
<f:setPropertyActionListener value="#{cpVilleBean.ville}" target="#{ville}" />
26.
</a4j:jsFunction>
27.
28.
<h:panelGroup layout="block" styleClass="cpGroup middle">
29.
<h:inputText id="#{idCp}" value="#{cp}"
30.
maxlength="5"
31.
styleClass="#{styleClass} cp smoothReadonly middle"
32.
readonly="#{readonly}"
33.
disabled="#{disabled}"
34.
onchange="#{onchange}" onfocus="#{onfocus}" onblur="#{onblur}"
35.
required="#{required}" label="Cp #{label}"
36.
tabindex="#{tabindex}"
37.
onkeyup="if ($(event).which != 16){ if (keeUtils.cpOK(this.value)) { searchCp_#{id}
(this.value); }}">
38.
</h:inputText>
39.
</h:panelGroup>
40.
<h:panelGroup layout="block" id="#{idGroupVille}" styleClass="villeGroup middle" >
41.
<h:inputText id="#{idVille}" value="#{ville}"
42.
style="width : #{villeWidth};"
43.
styleClass="#{styleClass} ville smoothReadonly"
44.
rendered="#{disabled or not empty ville or empty cpVilleBean.villes or empty cp}"
45.
readonly="#{readonly}"
- 14 -

Copyright 2015 Franck Gasparotto. Aucune reproduction, mme partielle, ne peut tre faite de ce site et de l'ensemble de son contenu : textes, documents,
images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu' trois ans de prison et jusqu' 300 000 de dommages et intrts.
http://keeleek.developpez.com/tutoriels/jsf/methodologie-creation-composant-richfaces-cp-ville/

Tutoriel sur la cration d'un composant JSF CP/Ville par Franck Gasparotto

/WebContent/composant/cpVille.xhtml

46.
disabled="#{disabled}"
47.
onchange="#{onchange}"
48.
onfocus="#{onfocus}"
49.
onblur="#{onblur}"
50.
required="#{required}" label="Ville #{label}"
51.
tabindex="#{tabindexSup}" />
52.
53.
<rich:autocomplete id="#{idVilles}" value="#{ville}"
54.
styleClass="middle"
55.
inputClass="#{styleClass} comboVille"
56.
rendered="#{(disabled)?'false': (not empty cpVilleBean.villes and empty ville and (jl:leng
57.
onchange="#{onchange}" onfocus="#{onfocus}" onblur="#{onblur}"
58.
disabled="#{disabled}"
59.
required="#{required}" label="Ville #{label}"
60.
tabindex="#{tabindexSup}"
61.
mode="client" showButton="true" selectFirst="true" autofill="true" layout="div"
62.
autocompleteList="#{cpVilleBean.villes}" var="vil" fetchValue="#{vil.value}" >
63.
#{vil.label}
64.
</rich:autocomplete>
65.
</h:panelGroup>
66.
</h:panelGroup>
67. </ui:composition>

Remarquez l'utilisation de l'oprateur ternaire qui me permet de spcifier des valeurs par dfaut
pour rendered, disabled, readonly, villeWidth et tabindexSup.
De plus pour simplifier la surcharge des styles de notre composant, j'ai cr une classe pour chaque lment qui
reprend le contenu de l'attribut style. J'ai concatn le paramtre styleClass l'attribut styleClass de chaque lment.
Les classes ont t externalises dans un fichier CSS que voici :
/WebContent/resources/default/css/cpVille.css
1. @CHARSET "UTF-8";
2. .middle {
3.
vertical-align: middle;}
4. .cp {
5.
width:55px;
6.
margin:0px;
7.
vertical-align:middle;}
8. .cpGroup {
9.
display:inline-block;}
10. .ville {
11.
margin:0px;}
12. .villeGroup {
13.
display:inline-block;
14.
margin:0px 0px 0px 3px;}

Ce fichier est inclus dans la facelet grce la balise <h:outputStylesheet>.


Dans l'exemple de l'adresse pro, pour surcharger la longueur du combo ville je dois maintenant crire l'instruction
CSS suivante :
1. <h:outputStylesheet>
2.
input.pro.comboVille { width: 186px; }
3. </h:outputStylesheet>

Enfin le code JavaScript utilis est inclus directement dans la facelet via la balise <h:outputScript>. Voici d'ailleurs
le code source de ce fichier :
/WebContent/resources/default/js/utils.js

1. var keeUtils = {
2.
cpOK : function(text) {
3.
return this.compareTextLength(text, 5) == 0 || this.compareTextLength(text, 0) == 0;
4.
},
5.
compareTextLength : function(text, length) {
- 15 -

Copyright 2015 Franck Gasparotto. Aucune reproduction, mme partielle, ne peut tre faite de ce site et de l'ensemble de son contenu : textes, documents,
images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu' trois ans de prison et jusqu' 300 000 de dommages et intrts.
http://keeleek.developpez.com/tutoriels/jsf/methodologie-creation-composant-richfaces-cp-ville/

Tutoriel sur la cration d'un composant JSF CP/Ville par Franck Gasparotto

/WebContent/resources/default/js/utils.js
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48. }

if (text.length > length)


return 1;
if (text.length < length)
return -1;
if (text.length == length)
return 0;

},
goToNextTabIndex : function(currentElmt) {
var ntabindex = parseFloat(currentElmt.getAttribute('tabindex'));
ntabindex++;
nbTentative = 0;
var nextField = this.getFieldByTabIndex(ntabindex);
while(nextField.length == 0 && nbTentative < 5) {
ntabindex++;
nextField = this.getFieldByTabIndex(ntabindex);
nbTentative++;
}
if(nextField.length != 0) {
nextField.focus();
}
},
goToPrevTabIndex : function(currentElmt) {
var ntabindex = parseFloat(currentElmt.getAttribute('tabindex'));
ntabindex--;
var prevField = this.getFieldByTabIndex(ntabindex);
if(prevField.length != 0) {
prevField.focus();
}
},
getFieldByTabIndex : function (ntabindex) {
var field = jQuery('input[tabindex='+ntabindex+']');
if(field.length == 0) {
field = jQuery('select[tabindex='+ntabindex+']');
if (field.length == 0) {
field = jQuery('textarea[tabindex='+ntabindex+']');
if (field.length == 0) {
field = jQuery('a[tabindex='+ntabindex+']');
}
}
}
return field;
}

V - Mthode 2 : Composant facelet composite


Pour crer le composant selon la deuxime mthode, nous allons crer un fichier dans le rpertoire /WebContent/
resources/composant.J'ai choisi composant de manire arbitraire, mais le dossier doit tre dans le
rpertoire resources.
/WebContent/resources/composant/cpVille.xhtml

1. <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1strict.dtd">


2. <html xmlns="http://www.w3.org/1999/xhtml"
3.
xmlns:h="http://java.sun.com/jsf/html"
4.
xmlns:f="http://java.sun.com/jsf/core"
5.
xmlns:ui="http://java.sun.com/jsf/facelets"
6.
xmlns:a4j="http://richfaces.org/a4j"
7.
xmlns:rich="http://richfaces.org/rich"
8.
xmlns:jl="http://java.sun.com/jsp/jstl/functions"
9.
xmlns:composite="http://java.sun.com/jsf/composite" >
10.
11.
<composite:interface>
12.
13.
<!-- Dclaration des attributs du composants -->
14.
15.
</composite:interface>
- 16 -

Copyright 2015 Franck Gasparotto. Aucune reproduction, mme partielle, ne peut tre faite de ce site et de l'ensemble de son contenu : textes, documents,
images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu' trois ans de prison et jusqu' 300 000 de dommages et intrts.
http://keeleek.developpez.com/tutoriels/jsf/methodologie-creation-composant-richfaces-cp-ville/

Tutoriel sur la cration d'un composant JSF CP/Ville par Franck Gasparotto

/WebContent/resources/composant/cpVille.xhtml

16.
17.
<composite:implementation>
18.
19.
<!-- Code source du composant -->
20.
21.
</composite:implementation>
22. </html>

La dclaration du namespace composite nous permet d'utiliser les lments interface et implementation qui
permettent respectivement de :

dclarer les attributs de notre composant ;


crire le code du composant.

Voici le code rsultant :


/WebContent/resources/composant/cpVille.xhtml
1.
2.
3.
4.

<composite:interface>
<composite:attribute name="id" required="true" />

<composite:attribute name="cp" required="true" type="java.lang.String" shortDescription="Bean Property for the c

<composite:attribute name="ville" required="true" type="java.lang.String" shortDescription="Bean Property for th


5.
<composite:attribute name="rendered" default="true" />
6.
<composite:attribute name="readonly" default="false" />
7.
<composite:attribute name="disabled" default="false" />
8.
<composite:attribute name="required" default="false" />
9.
<composite:attribute name="label" />
10.
<composite:attribute name="onchange" />
11.
<composite:attribute name="onfocus" />
12.
<composite:attribute name="onblur" />
13.
<composite:attribute name="villeWidth" default="170px" />
14.
<composite:attribute name="styleClass" />
15.
<composite:attribute name="tabindex" />
16.
</composite:interface>
17.
<composite:implementation>
18.
<h:outputStylesheet library="default" name="css/cpVille.css" />
19.
<h:outputScript library="default" name="js/utils.js" target="head" />
20.
21.
<h:panelGroup id="#{cc.attrs.id}" layout="block" rendered="#{cc.attrs.rendered}" styleClass="clearFloat middle">
22.
<ui:param name="idCp" value="#{cc.attrs.id}_cp" />
23.
<ui:param name="idVille" value="#{cc.attrs.id}_ville" />
24.
<ui:param name="idVilles" value="#{cc.attrs.id}_villes" />
25.
<ui:param name="idGroupVille" value="#{cc.attrs.id}_pgVille" />
26.
<ui:param name="idGroupVille" value="#{cc.attrs.id}_pgVille" />
27.
<ui:param name="tabindexSup" value="#{(cc.attrs.tabindex==null) ? '' : cc.attrs.tabindex + 1}" />
28.
<ui:param name="villeWidth" value="width : #{cc.attrs.villeWidth}" />
29.
30.
<a4j:jsFunction id="fCp_#{id}" name="searchCp_#{id}" immediate="true" render="#{idGroupVille}" limitRender="true
31.
oncomplete="keeUtils.goToNextTabIndex( #{rich:element(idCp)} );" >
32.
<a4j:param name="param1" assignTo="#{cp}" />
33.
<f:setPropertyActionListener value="#{cp}" target="#{cpVilleBean.cp}" />
34.
<f:setPropertyActionListener value="#{cpVilleBean.ville}" target="#{ville}" />
35.
</a4j:jsFunction>
36.
37.
<h:panelGroup layout="block" styleClass="cpGroup middle">
38.
<h:inputText id="#{idCp}" value="#{cc.attrs.cp}"
39.
maxlength="5"
40.
styleClass="#{cc.attrs.styleClass} cp smoothReadonly middle"
41.
readonly="#{cc.attrs.readonly}"
42.
disabled="#{cc.attrs.disabled}"
43.
onchange="#{cc.attrs.onchange}" onfocus="#{cc.attrs.onfocus}" onblur="#{cc.attrs.onblur}"
44.
required="#{cc.attrs.required}" label="Cp #{cc.attrs.label}"
45.
tabindex="#{cc.attrs.tabindex}"

- 17 -

Copyright 2015 Franck Gasparotto. Aucune reproduction, mme partielle, ne peut tre faite de ce site et de l'ensemble de son contenu : textes, documents,
images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu' trois ans de prison et jusqu' 300 000 de dommages et intrts.
http://keeleek.developpez.com/tutoriels/jsf/methodologie-creation-composant-richfaces-cp-ville/

Tutoriel sur la cration d'un composant JSF CP/Ville par Franck Gasparotto

/WebContent/resources/composant/cpVille.xhtml

46.
onkeyup="if ($(event).which != 16)
{ if (keeUtils.cpOK(this.value)) { searchCp_#{id}(this.value); }}">
47.
</h:inputText>
48.
</h:panelGroup>
49.
<h:panelGroup layout="block" id="#{idGroupVille}" styleClass="villeGroup middle" >
50.
<h:inputText id="#{idVille}" value="#{ville}"
51.
style="#{villeWidth};"
52.
styleClass="#{cc.attrs.styleClass} ville smoothReadonly"
53.
rendered="#{cc.attrs.disabled or not empty cc.attrs.ville or empty cpVilleBean.villes
54.
readonly="#{cc.attrs.readonly}"
55.
disabled="#{cc.attrs.disabled}"
56.
onchange="#{cc.attrs.onchange}"
57.
onfocus="#{cc.attrs.onfocus}"
58.
onblur="#{cc.attrs.onblur}"
59.
required="#{cc.attrs.required}" label="Ville #{cc.attrs.label}"
60.
tabindex="#{tabindexSup}" />
61.
62.
<rich:autocomplete id="#{idVilles}" value="#{ville}"
63.
styleClass="middle"
64.
inputClass="#{cc.attrs.styleClass} comboVille"
65.
rendered="#{(cc.attrs.disabled) ? false : (not empty cpVilleBean.villes and empty cc.a
66.
onchange="#{cc.attrs.onchange}" onfocus="#{cc.attrs.onfocus}" onblur="#{cc.attrs.onblu
67.
disabled="#{cc.attrs.disabled}" required="#{cc.attrs.required}" label="Ville #{cc.attr
68.
tabindex="#{tabindexSup}"
69.
mode="client" showButton="true" selectFirst="true" autofill="true" autocompleteList="#
70.
#{vil.label}
71.
</rich:autocomplete>
72.
</h:panelGroup>
73.
</h:panelGroup>
74.
</composite:implementation>

Compare la premire mthode, cette syntaxe offre les avantages suivants en termes de lisibilit :

aperu exhaustif de tous les attributs possibles en lisant la partie interface (<composite:attribute>) ;
revue rapide des attributs obligatoires via required ;
revue rapide des valeurs par dfaut via default ;
revue rapide du type de donne attendu pour les proprits de bean via type ;
vue sur l'utilit de l'attribut via shortDescription.

Les attributs dclars peuvent tre rfrencs dans le code source implementation en utilisant la
syntaxe #{cc.attrs.nom_attr}.
Pour utiliser le composant, il faut dclarer un namespace qui pointe vers le sous-dossier de resources dans lequel
se trouve notre composant :
Namespace "kee"

1. <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1strict.dtd">


2. <html
3.
xmlns="http://www.w3.org/1999/xhtml"
4.
xmlns:ui="http://java.sun.com/jsf/facelets"
5.
xmlns:h="http://java.sun.com/jsf/html"
6.
xmlns:f="http://java.sun.com/jsf/core"
7.
xmlns:rich="http://richfaces.org/rich"
8.
xmlns:a4j="http://richfaces.org/a4j"
9.
xmlns:kee="http://java.sun.com/jsf/composite/composant" >

Ensuite pour l'inclure dans la page, il faut simplement prfixer le nom du fichier par le namespace et dclarer les
attributs requis et optionnels.
1. <h:panelGrid columns="2" >
2.
3.
<h:outputLabel value="Adresse " for="perso_adresse" />
4.
<h:inputText id="perso_adresse" value="#{exempleCpVilleBean.persoAdresse}"

- 18 -

Copyright 2015 Franck Gasparotto. Aucune reproduction, mme partielle, ne peut tre faite de ce site et de l'ensemble de son contenu : textes, documents,
images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu' trois ans de prison et jusqu' 300 000 de dommages et intrts.
http://keeleek.developpez.com/tutoriels/jsf/methodologie-creation-composant-richfaces-cp-ville/

Tutoriel sur la cration d'un composant JSF CP/Ville par Franck Gasparotto

5.
style="width: 300px"/>
6.
7.
<h:panelGroup>
8.
<h:outputLabel value="CP " for="perso_cp" />/
9.
<h:outputLabel value=" Ville" for="perso_ville" />
10.
</h:panelGroup>
11.
12.
<kee:cpVille id="perso"
13.
cp="#{exempleCpVilleBean.persoCp}"
14.
ville="#{exempleCpVilleBean.persoVille}"
15.
villeWidth="238px"
16.
styleClass="perso"
17.
tabindex="5"
18.
onchange="notifyChange()" />
19. </h:panelGrid>

Compare la premire mthode, l'utilisation d'un composant composite nous fait bnficier de l'autocompltion lors
de l'criture du code et les descriptions des attributs shortDescriptionseront rendues lisibles par votre IDE.
Je reviens sur la syntaxe de dfinition du composant. Jusqu'ici, j'ai adapt mon composant rsultant de la mthode
par inclusion pour crer un composant composite. En fait, le fonctionnement des composants composites me permet
de simplifier quelques dclarations.
1

Attributs implicites
Les attributs id et rendered n'ont pas besoin d'tre dclars et ne devraient pas l'tre, car ils sont
implicitement hrits du composant de base dont hritent tous les composants composites.
Je peux nanmoins laisser la dclaration de id pour obliger le dveloppeur le dfinir.
Pour utiliser l'id dans l'implmentation, il est possible d'utiliser la syntaxe #{cc.id}.
Gnration des id
Tous les sous-composants JSF qui constituent le composant composite auront un id de la forme suivante :
idFormulaire:idComposant:idSousComposant.
Exemple : fCpVil:perso:cp
Je n'ai donc plus besoin des quatre paramtres idCp, idVille, idVilles, idGroupeVille qui permettaient d'avoir des
id uniques pour la mthode 1 par inclusion.
Pour utiliser un label qui pointe vers un sous-composant, il faut dfinir son attribut for
avec la syntaxe idComposant:idSousComposant.

Exemple pour cp : <h:label value="CP :" for="perso:cp" />


Rfrencement AJAX
Du fait du point prcdent, le div conteneur du composant ne portera pas l'id saisi. Sur l'exemple de
perso , il sera gnr de la manire suivante : fCpVil:perso:perso.
Du coup, dans la page principale, il n'est plus possible de faire rfrence au composant dans les requtes
Ajax via execute et render.
Pour rsoudre ce problme, il faut encapsuler la partie implmentation dans un <div> ou un <span> dont l'id
est #{cc.clientId}.
J'ai donc remplac le premier h:panelGroup par un div.

Finalement, le code du composant est le suivant :


/WebContent/resources/composant/cpVille.xhtml

1. <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1strict.dtd">


2. <html xmlns="http://www.w3.org/1999/xhtml"
3.
xmlns:h="http://java.sun.com/jsf/html"
4.
xmlns:f="http://java.sun.com/jsf/core"
5.
xmlns:ui="http://java.sun.com/jsf/facelets"
6.
xmlns:a4j="http://richfaces.org/a4j"
7.
xmlns:rich="http://richfaces.org/rich"
8.
xmlns:jl="http://java.sun.com/jsp/jstl/functions"
9.
xmlns:fct="http://www.alladin.fr/socaf"

- 19 -

Copyright 2015 Franck Gasparotto. Aucune reproduction, mme partielle, ne peut tre faite de ce site et de l'ensemble de son contenu : textes, documents,
images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu' trois ans de prison et jusqu' 300 000 de dommages et intrts.
http://keeleek.developpez.com/tutoriels/jsf/methodologie-creation-composant-richfaces-cp-ville/

Tutoriel sur la cration d'un composant JSF CP/Ville par Franck Gasparotto

/WebContent/resources/composant/cpVille.xhtml

10.
xmlns:composite="http://java.sun.com/jsf/composite" >
11.
12.
<composite:interface>
13.
<composite:attribute name="id" required="true" />
14.
<composite:attribute name="cp" required="true" type="java.lang.String" shortDescription="Bean Property for the c
15.
<composite:attribute name="ville" required="true" type="java.lang.String" shortDescription="Bean Property for th
16.
<composite:attribute name="readonly" default="false" />
17.
<composite:attribute name="disabled" default="false" />
18.
<composite:attribute name="required" default="false" />
19.
<composite:attribute name="label" />
20.
<composite:attribute name="onchange" />
21.
<composite:attribute name="onfocus" />
22.
<composite:attribute name="onblur" />
23.
<composite:attribute name="villeWidth" default="170px" />
24.
<composite:attribute name="styleClass" />
25.
<composite:attribute name="tabindex" />
26.
</composite:interface>
27.
<composite:implementation>
28.
<h:outputStylesheet library="default" name="css/cpVille.css" />
29.
<h:outputScript library="default" name="js/utils.js" target="head" />
30.
31.
<div id="#{cc.clientId}" class="clearFloat middle" >
32.
33.
<ui:param name="tabindexSup" value="#{(cc.attrs.tabindex==null) ? '' : cc.attrs.tabindex + 1}" />
34.
<ui:param name="villeWidth" value="width : #{cc.attrs.villeWidth}" />
35.
36.
<a4j:jsFunction id="fCp" name="searchCp_#{cc.id}" immediate="true" render="pgVille" limitRender="true"
37.
oncomplete="keeUtils.goToNextTabIndex( #{rich:element('cp')} );" >
38.
<a4j:param name="param1" assignTo="#{cc.attrs.cp}" />
39.
<f:setPropertyActionListener value="#{cc.attrs.cp}" target="#{cpVilleBean.cp}" />
40.
<f:setPropertyActionListener value="#{cpVilleBean.ville}" target="#{cc.attrs.ville}" />
41.
</a4j:jsFunction>
42.
43.
<h:panelGroup layout="block" styleClass="cpGroup middle">
44.
<h:inputText id="cp" value="#{cc.attrs.cp}"
45.
maxlength="5"
46.
styleClass="#{cc.attrs.styleClass} cp smoothReadonly middle"
47.
readonly="#{cc.attrs.readonly}"
48.
disabled="#{cc.attrs.disabled}"
49.
onchange="#{cc.attrs.onchange}" onfocus="#{cc.attrs.onfocus}" onblur="#{cc.attrs.onblur}"
50.
required="#{cc.attrs.required}" label="Cp #{cc.attrs.label}"
51.
tabindex="#{cc.attrs.tabindex}"
52.
onkeyup="if ($(event).which != 16)
{ if (keeUtils.cpOK(this.value)) { searchCp_#{cc.id}(this.value); }}">
53.
</h:inputText>
54.
</h:panelGroup>
55.
<h:panelGroup layout="block" id="pgVille" styleClass="villeGroup middle" >
56.
<h:inputText id="ville" value="#{cc.attrs.ville}"
57.
style="#{villeWidth};"
58.
styleClass="#{cc.attrs.styleClass} ville smoothReadonly"
59.
rendered="#{cc.attrs.disabled or not empty cc.attrs.ville or empty cpVilleBean.villes
60.
readonly="#{cc.attrs.readonly}"
61.
disabled="#{cc.attrs.disabled}"
62.
onchange="#{onchange}"
63.
onfocus="#{onfocus}"
64.
onblur="#{onblur}"
65.
required="#{cc.attrs.required}" label="Ville #{cc.attrs.label}"
66.
tabindex="#{tabindexSup}" />
67.
68.
<rich:autocomplete id="villes" value="#{cc.attrs.ville}"
69.
styleClass="middle"
70.
inputClass="#{cc.attrs.styleClass} comboVille"
71.
rendered="#{(cc.attrs.disabled) ? false : (not empty cpVilleBean.villes and empty cc.a
72.
onchange="#{cc.attrs.onchange}" onfocus="#{cc.attrs.onfocus}" onblur="#{cc.attrs.onblu
73.
disabled="#{cc.attrs.disabled}" required="#{cc.attrs.required}" label="Ville #{cc.attr
74.
tabindex="#{tabindexSup}"
- 20 -

Copyright 2015 Franck Gasparotto. Aucune reproduction, mme partielle, ne peut tre faite de ce site et de l'ensemble de son contenu : textes, documents,
images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu' trois ans de prison et jusqu' 300 000 de dommages et intrts.
http://keeleek.developpez.com/tutoriels/jsf/methodologie-creation-composant-richfaces-cp-ville/

Tutoriel sur la cration d'un composant JSF CP/Ville par Franck Gasparotto

/WebContent/resources/composant/cpVille.xhtml

75.
mode="client" showButton="true" selectFirst="true" autofill="true" autocompleteList="#
76.
#{vil.label}
77.
</rich:autocomplete>
78.
</h:panelGroup>
79.
</div>
80.
</composite:implementation>
81. </html>

VI - Conclusion
Voil, nous avons boucl cet article sur la cration d'un composant en JSF.
Aprs avoir expliqu le fonctionnement du composant exemple CP/Ville, nous avons list les paramtres, puis crer
le composant de deux manires diffrentes : d'une part en utilisant le principe d'inclusion de facelet et d'autre part en
utilisant le principe des composants composites (composite components).
Cependant, je ne peux utiliser le composant sans inclure CpVilleBean dans mon projet. Afin de dporter la logique
mtier dans le composant, il faudrait utiliser le principe de NamingContainer que je dvelopperai dans un futur tutoriel.
Ressources :

JSF 2 fu, Part 2: Templating and composite components


JSF 2 fu: Best practices for composite components

VII - Remerciements
Cet article a t publi avec l'aimable autorisation de la socit
composant-jsf-cp-ville) peut tre vu sur le blog/site de keeleek.

keeleek et l'article d'origine (tutoriel-creation-

Nous tenons remercier Mickael Baron pour la mise au gabarit, Olivier Butterlin pour la relecture technique et
Claude Leloup pour la relecture orthographique.

- 21 -

Copyright 2015 Franck Gasparotto. Aucune reproduction, mme partielle, ne peut tre faite de ce site et de l'ensemble de son contenu : textes, documents,
images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu' trois ans de prison et jusqu' 300 000 de dommages et intrts.
http://keeleek.developpez.com/tutoriels/jsf/methodologie-creation-composant-richfaces-cp-ville/

Vous aimerez peut-être aussi