Vous êtes sur la page 1sur 147

,

Programmation Web Côté Client


avec JavaScript et jQuery

Rémy Malgouyres
LIMOS UMR 6158, IUT, département info
Université Clermont 1
B.P. 86
63172 AUBIERE cedex
http ://http ://malgouyres.org/
Table des matières

1 Premiers pas en JavaScript 5


1.1 Balise <script> et Hello world en JavaScript . . . . . . . . . . . . . . . . . . 5
1.2 Types, variables et portée . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
1.3 Fonctions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
1.4 Objets . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
1.5 Tableaux (le type Array) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
1.6 Exemple : traitement d’un formulaire avec jQuery . . . . . . . . . . . . . . . . 13

2 Programmation Fonctionnelle et Objet en JavaScript 16


2.1 Le Pattern Module . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
2.2 Passage d’arguments par objets . . . . . . . . . . . . . . . . . . . . . . . . . . 19
2.3 Exemple de fabrique sommaire . . . . . . . . . . . . . . . . . . . . . . . . . . 20
2.4 Structuration d’une application . . . . . . . . . . . . . . . . . . . . . . . . . . 21
2.5 Exemple : un module metier.regexUtil . . . . . . . . . . . . . . . . . . . . . 23
2.6 Module Métier adresse . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27
2.7 Création d’un Module myApp.view.adresse . . . . . . . . . . . . . . . . . . . 37

3 Constructeurs, Prototype et Patterns Associés 41


3.1 Constructeurs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41
3.2 Prototypes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42
3.3 Exemple : assurer l’implémentation d’interfaces . . . . . . . . . . . . . . . . . 45
3.4 Fabrique d’Objets Métier avec prototype . . . . . . . . . . . . . . . . . . . . . 47
3.5 Patterns pseudo-classique (à éviter) . . . . . . . . . . . . . . . . . . . . . . . . 55

4 Interfaces Hommes Machines (IHM ) 58


4.1 Filtrage Basique des Inputs d’un Formulaire . . . . . . . . . . . . . . . . . . . 58
4.2 Pattern Mediator pour le filtrage d’attributs . . . . . . . . . . . . . . . . . . . 60
4.3 Exemple : génération automatique de formulaire d’adresse . . . . . . . . . . . 64

5 Exemple d’Application Interactive 71


5.1 Principe de l’application et analyse fonctionnelle . . . . . . . . . . . . . . . . . 71
5.2 Modèle de donnée . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71
5.3 Pattern Mediator : centraliser les événements . . . . . . . . . . . . . . . . . . 74
5.4 Événements concernant les personnes . . . . . . . . . . . . . . . . . . . . . . . 77
5.5 Événements concernant les Adresses . . . . . . . . . . . . . . . . . . . . . . . . 90

1
TABLE DES MATIÈRES

6 Requêtes Asynchrones et API Restful 99


6.1 Qu’est-ce qu’une requête asynchrone ? . . . . . . . . . . . . . . . . . . . . . . 99
6.2 Requête Ajax . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 100
6.3 Qu’est-ce qu’une API REST (ou systèmes Restful) ? . . . . . . . . . . . . . . . 103
6.4 Exemple d’API Restful . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 103
6.5 Persistance avec AJAX . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 114

A Graphisme avec les Canvas HTML5 126


A.1 Notion de canvas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 126
A.2 Exemple d’animation dans un canvas . . . . . . . . . . . . . . . . . . . . . . . 127

B Programmation Événementielle en JavaScript 129


B.1 Rappel sur la Gestion d’Événements en CSS . . . . . . . . . . . . . . . . . . . 129
B.2 Événements en Javascript . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 130

C Gestion des fenêtres 135


C.1 Charger un nouveau document . . . . . . . . . . . . . . . . . . . . . . . . . . 135
C.2 Naviguer dans l’historique . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 136
C.3 Ouvrir une nouvelle fenêtre (popup) . . . . . . . . . . . . . . . . . . . . . . . 137

D Document Object Model (DOM) 138


D.1 Qu’est-ce que le DOM ? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 138
D.2 Sélection et Manipulation de Base sur le DOM . . . . . . . . . . . . . . . . . . 139

2
Architectures client/serveur et API

Architecture d’une application multi plate-formes


Une application multi plate-formes contemporaine cherchera à se structurer suivant (voir fi-
gure 1) :

1. Une application sur un serveur (API ) qui traitera les données et assurera la persistance ;

2. Une application sur chaque type de client, qui utilise ce serveur via des requêtes, et gère
l’interface (par exemple une Interface Homme Machine (IHM)).

Acteur API Base de


secondaires Serveur HTTP données
s

do
ée

requêtes
données

re
es
nn

nn
qu
êt
do

ée
qu

êt

s
es
re

Client Client Appli. etc.


Mobile Web Tierce

Figure 1 : La structure typique d’une application multi plate-formes

On aura dans la mesure du possible intérêt à limiter le plus possible le travail côté client
pour les raisons suivantes :

1. L’implémentation côté client dépend de la plate-forme et l’implémentation sur le serveur


constitue un forme de factorisation du code.

2. Sur certaines plate-formes, comme dans le cas des applications web en JavaScript, la
sécurité et la confidentialité côté client sont très mauvaises, alors que nous pouvons
implémenter la sécurité côté serveur.

Cependant, dans la mesure du possible, les opérations peu sensible, par exemple concernant
l’ergonomie, se feront côté client pour limiter les coûts d’infrastructure (nombre de serveurs...)
et améliorer la réactivité de l’application.

3
TABLE DES MATIÈRES

Le cas de l’application Web


Dans ce cours, nous étudions le développement d’applications Web (auxquelles on accède via
un navigateur internet), avec une architecture client/serveur dans laquelle (voir la figure 2) :

• Notre API est un serveur HTTP implémenté en PHP avec une architecture MVC et
DAL ;

• Notre application côté client est en JavaScript (qui s’est imposé comme un langage stan-
dard côté client), et utilise la librairie jQuery pour la gestion des événements, des vues,
et des interactions (requêtes et échange de données au format JSON ) avec le serveur.

Client : IHM requêtes Serveur : API


points d’entrée et actions
événements utilisateur GET, POST, PUT, DELETE persistance
architecture MVC
requêtes asynchrones BD
données
parse/génère JSON Driver de BD
parse/génère JSON
JSON architecture DAL (génér./exec. SQL)
génération vues HTML

Figure 2 : L’architecture client/serveur de notre application Web

4
Chapitre 1

Premiers pas en JavaScript

1.1 Balise <script> et Hello world en JavaScript


Une première manière d’insérer un script JavaScript dans un fichier HTML est de mettre le
code JavaScript dans une balise <script></script>. On a alors accès au document dans le
code JavaScript et on peut sortir du code HTML :

exemples/bases/ex01_helloWorld.html
1 /<! d o c t y p e HTML>
2 <html lang=” f r ”>
3 <head>
4 <meta charset=”UTF−8” />
5 <t i t l e>H e l l o World en J a v a s c r i p t</ t i t l e>
6 </head>
7 <body>
8 <p>
9 <s c r i p t>
10 document . w r i t e ( ” H e l l o w o r l d ! ” ) ;
11 </s c r i p t>
12 <p>
13 </body>
14 </html>

Une première manière d’insérer un script JavaScript dans un fichier HTML est de mettre le
code JavaScript dans un fichier .js séparé, qui est inclus dans le HTML au niveau du header
par une balise <script src=''...''></script>.

exemples/bases/ex02_helloWorld.html
1 /<! d o c t y p e HTML>
2 <html lang=” f r ”>
3 <head>
4 <meta charset=”UTF−8” />
5 <t i t l e>H e l l o World en J a v a s c r i p t</ t i t l e>
6 <s c r i p t src=” . / e x 0 2 _ h e l l o Wo r l d . j s ”></s c r i p t>
7 </head>
8 <body>
9 </body>
10 </html>

5
Rémy Malgouyres, http://malgouyres.org Programmation Web Côté Client, JS et jQuery

exemples/bases/ex02_helloWorld.js
1 a l e r t ( ” H e l l o World ! ” ) ;

Dans ce dernier cas, on n’a pas accès au document dans le fichier JavaScript, mais il y a
d’autres avantages (factorisation et mise en cache du code JavaScript partagé entre plusieurs
pages HTML par exemple).

1.2 Types, variables et portée


Le JavaScript est un langage faiblement typé, car on n’indique pas le type des variables lors
de la déclaration. Lors le la déclaration des variables, le type est fixé implicitement par le type
de la donnée affectée à la variable.
La déclaration de la variable peut contenir ou non le mot clef var. Un variable déclarée
avec le mot clef var (on parle de déclaration explicite) est locale à la fonction où la variable
est déclarée. Une variable déclarée sans le mot clef var (on parle de déclaration implicite) est
globale.
Il n’y a pas, contrairement au C++ ou Java, de visibilité locale à un bloc. Un variable
déclarée n’importe où dans une fonction est visible dans toute la fonction au moins. Pour cette
raison, on déclarera systématiquement les variables locales à la fonction au début du corps de la
fonction, contrairement aux bonnes pratiques dans d’autres langages où on déclare la variable
au plus près de son point de première utilisation.
Dans les programmes assez gros structurés en modules ou packages, on peut créer en JavaS-
cript l’équivalent d’un namespace par un patron de conception consistant à mettre le code de
l’ensemble d’un module dans le corps de définition d’une fonction ou dans un littéral définissant
un objet (voir plus loin pour la notion d’objet).

1.3 Fonctions
Les fonctions en JavaScript sont déclarées par le mot clef function. c’est un type de données
comme un autre, et une fonction peut ainsi être affectée à une variable. Voici un exemple de
fonction qui calcule le prix TTC d’un produit à partir de son prix hors taxes. Comme les
paramètres des fonctions ne sont pas typés, on peut vérifier le type des paramètres dans la
fonction et éventuellement renvoyer une exception si le type du paramètre effectif n’est pas le
bon.

exemples/bases/ex03_function.html
1 <! doctype HTML>
2 <html l a n g=” f r ”>
3 <head>
4 <meta c h a r s e t=”UTF−8” />
5 <t i t l e>F o n c t i o n s</ t i t l e>
6 </head>
7 <body>
8 <p>
9 <s c r i p t>
10 // Dé c l a r a t i o n d ’ une v a r i a b l e de t y p e f o n c t i o n
11 var calculPrixTTC = function ( prixHT , tauxTVA ) {
12 i f ( ! ( typeof prixHT == ” number ” ) | | ! ( typeof tauxTVA == ” number ” ) ) {

6
Chapitre 1 : Premiers pas en JavaScript

13 throw new E r r o r ( ” Function calculPrixTTC a p p e l é e a v e c paramètre i n c o r r e c t . ”


)
14 }
15 return prixHT *(1.0+tauxTVA / 1 0 0 . 0 ) ;
16 };
17
18 // Appel c o r r e c t de l a f o n c t i o n :
19 try {
20 document . w r i t e ( ” P r i x TTC : ” + calculPrixTTC ( 1 8 0 . 0 , 1 9 . 6 ) ) ;
21 } catch ( e r r ) {
22 alert ( err ) ;
23 }
24
25 // Appel i n c o r r e c t de l a f o n c t i o d é c l e n c a h n t une e x c e p t i o n :
26 try {
27 document . w r i t e ( ” P r i x TTC : ” + calculPrixTTC ( ” coucou ” , 1 9 . 6 ) ) ;
28 } catch ( e r r ) {
29 alert ( err ) ;
30 }
31 </s c r i p t>
32 <p>
33 </body>
34 </html>

Notons que l’on peut aussi déclarer une fonction un peu comme en PHP de la manière
suivante :

1 function myFunction (myParam) {


2 return (myParam < 0 ) ;
3 }

mais la fonction est alors globale (son nom existe dans tout le programme). La bonne pratique
consiste à déclarer les éléments d’un programme de sorte qu’ils aient la portée la plus locale
possible, donc à déclarer la fonction avec le mot clé var comme dans le premier exemple de
fonction ci-dessus.

1.4 Objets
Un objet JavaScript rassemble plusieurs propriétés, qui peuvent être des données, d’autres
objets, ou encore des fonctions, alors appelées méthodes. Un objet n’est ni tout à fait une
structure comme en C, ni tout à fait une classe comme dans un langage objet classique. Par
exemple, un objet JavaScript n’a pas de visibilité (privée, public) pour ses propriétés. Par
ailleurs, le principal mécanisme d’héritage en JavaScript se fait par la notion de prototype et
est très différent de l’héritage dans les langages objet classiques. Là encore, on peut mimer une
notion de visibilité via des patrons de conception.
Les noms de propriétés peuvent être

• Soit une chaîne de caractère (comme ”nom de propriété !”) quelconque (respecter les
doubles quotes dans un tel cas).

7
Rémy Malgouyres, http://malgouyres.org Programmation Web Côté Client, JS et jQuery

• Soit des noms légaux (commençant par une lettre suivi par une suite de lettres, chiffres,
et underscores (caractère _) auquel cas les doubles quotes sont optionnelles pour désigner
le nom.

1.4.1 Création d’un objet au moyen d’un littéral


On peut créer un nouvel objet par un littéral, en définissant ses propriétés des accolades {}. On
met alors chaque nom de propriété suivi d’un : suivi de la valeur de la propriété. Les propriétés
ainsi construites sont séparées par des virgules.

exemples/bases/ex04_objectLitteral.html
1 <! doctype HTML>
2 <html l a n g=” f r ”>
3 <head>
4 <meta c h a r s e t=”UTF−8” />
5 <t i t l e>O b j e t s</ t i t l e>
6 </head>
7 <body>
8 <p>
9 <s c r i p t>
10 // L i t t é r a l d é f i n i s s a n t un o b j e t :
11 var p r o d u i t = {
12 ” denomination ” : ” Notebook s o u s Ubuntu 4 c o r e s 2 . 0GB” ,
13 ” prixHT ” : 1 8 0 . 0 ,
14 ”tauxTVA” : 1 9 . 6
15 };
16
17 // Dé c l a r a t i o n d ’ une f o n c t i o n a v e c un paramètre :
18 var calculPrixTTC = function ( prod ) {
19 // Test d ’ e x i s t e n c e d e s p r o p r i é t é s de l ’ o b j e t :
20 i f ( ” prixHT ” in prod && ”tauxTVA” in prod ) {
21 return prod . prixHT *(1.0+ prod . tauxTVA / 1 0 0 . 0 ) ;
22 } else {
23 // R e j e t d ’ une e x c e p t i o n p e r s o n n a l i s é e :
24 // On r e j e t t e un o b j e t a v e c une prop . ”name” e t une prop . ” message ” .
25 throw {name : ”Bad Parameter ” ,
26 message : ” Mauvais t y p e de paramètre pour l a f o n c t i o n calculPrixTTC
”};
27 }
28 };
29
30 // E s s a i d ’ a p p e l de l a f o n c t i o n
31 try {
32 document . w r i t e ( ” P r i x TTC du p r o d u i t \” ”+p r o d u i t . denomination
33 +” \” : ”+calculPrixTTC ( p r o d u i t ) ) ;
34 } catch ( e ) { // a f f i c h a g e de l ’ e x c e p t i o n p e r s o n n a l i s é e .
35 a l e r t ( ”Une e r r e u r \” ” + e . name + ” \” s ’ e s t p r o d u i t e :\n”
36 + e . message ) ;
37 }
38 </s c r i p t>
39 <p>
40 </body>
41 </html>

8
Chapitre 1 : Premiers pas en JavaScript

Un objet peut contenir des propriétés qui sont de type function. On parle alors de méthode
de l’objet. Dans une méthode, on accède aux propriétés des l’objet grâce à l’identificateur this,
désignant l’objet auquel appartien la méthode.

exemples/bases/ex05_objectMethod.html
1 <! doctype HTML>
2 <html l a n g=” f r ”>
3 <head>
4 <meta c h a r s e t=”UTF−8” />
5 <t i t l e>O b j e t s</ t i t l e>
6 </head>
7 <body>
8 <s c r i p t>
9 var p r o d u i t = {
10 ” denomination ” : ” Notebook s o u s Ubuntu 4 c o r e s 2 . 0GB” ,
11 ” prixHT ” : 1 8 0 . 0 ,
12 ”tauxTVA” : 1 9 . 6 ,
13
14 // Dé f i n i t i o n d ’ une mé t h o d e :
15 getPrixTTC : function ( ) {
16 return t h i s . prixHT *(1.0+ t h i s . tauxTVA / 1 0 0 . 0 ) ;
17 }
18 };
19
20 // Fo n c ti o n dans l e c o n t e x t e g l o b a l
21 var getHtmlObjet = function ( o b j e t ) {
22 var c h a i n e = ” ” ;
23 // Parcours de t o u t e s l e s p r o p r i é t é s de l ’ o b j e t ( s t y l e ” f o r e a c h ”) :
24 f or (nom in o b j e t ) {
25 c h a i n e += ” o b j e t [ \ ” ”+nom+” \ ” ] = ”+o b j e t [ nom]+ ”<br />” ;
26 }
27 return c h a i n e ;
28 };
29
30 // a p p e l d ’ une f o n c t i o n d é f i n i e dans l e c o n t e x t e g l o b a l :
31 document . w r i t e ( ”<p>” + getHtmlObjet ( p r o d u i t ) + ”</p>” ) ;
32
33 // a p p e l d ’ une mé t h o d e :
34 document . w r i t e ( ”<p>P r i x TTC : ” + p r o d u i t . getPrixTTC ( ) + ”</p>” ) ;
35 </s c r i p t>
36 </body>
37 </html>

Une méthode d’objet JavaScript n’est pas tout à fait comme une méthode d’un langage à
objet classique, car la méthode JavaScript existe en autant d’exemplaires qu’il y a d’instance
des objets. Nous verrons plus loin la notion de prototype, qui permet de crée des méthodes qui
existent en un seul exemplaire pour toute une classe d’objets ayant les mêmes propriétés.

exemples/bases/ex06_nestedObjects.html
1 <! doctype HTML>
2 <html l a n g=” f r ”>
3 <head>
4 <meta c h a r s e t=”UTF−8” />
5 <t i t l e>O b j e t s</ t i t l e>
6 </head>

9
Rémy Malgouyres, http://malgouyres.org Programmation Web Côté Client, JS et jQuery

7 <body>
8 <s c r i p t>
9 var p r o d u i t = {
10 denomination : ” Notebook s o u s Ubuntu ” ,
11 prixHT_base : 1 8 0 . 0 ,
12 tauxTVA : 2 0 . 0 ,
13 // O b j e t ” n i c h é ” dans un sur−o b j e t
14 options : {
15 p r o c e s s o r : ” I n t e l 4 c o r e s 2 . 5 Ghz” ,
16 memory : ”4GB” ,
17 ” p r i x s u p p l é m e n t a i r e HT” : 5 0 . 0 ,
18 getHtml : function ( ) {
19 return t h i s . p r o c e s s o r + ” ” + t h i s . memory +
20 ” ( s u p p l é ment : ” + t h i s [ ” p r i x s u p p l é m e n t a i r e HT” ] + ” &euro ; ) ” ;
21 }
22 },
23 // Dé f i n i t i o n d ’ une mé t h o d e :
24 getHtml : function ( ) {
25 return t h i s . denomination +
26 ”<br />p r i x TTC t o u t compris : ”
27 + ( t h i s . prixHT_base + ( t h i s . o p t i o n s [ ” p r i x s u p p l é m e n t a i r e HT” ] | |
0.0) )
28 *(1.0+ t h i s . tauxTVA / 1 0 0 . 0 )
29 + ” &euro ;<br />” + t h i s . o p t i o n s . getHtml ( ) + ”<br />” ;
30 }
31 };
32
33 // a p p e l d ’ une mé t h o d e :
34 document . w r i t e ( ”<p>” + p r o d u i t . getHtml ( ) + ”</p>” ) ;
35 </s c r i p t>
36 </body>
37 </html>

1.4.2 Constructeur d’objets, mot réservé new


On peut créer un objet via le constructeur Object. Voici un exemple où l’on crée un objet
qui représente un produit. On crée ensuite une fonction qui calcule le prix TTC de ce produit
après avoir testé l’existence d’attributs.

exemples/bases/ex07_objectNew.html
1 <! doctype HTML>
2 <html l a n g=” f r ”>
3 <head>
4 <meta c h a r s e t=”UTF−8” />
5 <t i t l e>O b j e t s</ t i t l e>
6 </head>
7 <body>
8 <p>
9 <s c r i p t>
10 var p r o d u i t = new Object ( ) ;
11 p r o d u i t . denomination = ” Notebook s o u s Ubuntu 4 c o r e s 2 . 0GB” ;
12 p r o d u i t . prixHT = 1 8 0 . 0 ;
13 p r o d u i t . tauxTVA = 2 0 . 0 ;
14

10
Chapitre 1 : Premiers pas en JavaScript

15 var calculPrixTTC = function ( prod ) {


16 i f ( ” prixHT ” in prod && ”tauxTVA” in prod ) {
17 return prod . prixHT *(1.0+ prod . tauxTVA / 1 0 0 . 0 ) ;
18 } else {
19 throw new E r r o r ( ” Mauvais t y p e de paramètre pour l a f o n c t i o n calculPrixTTC ”
);
20 }
21 }
22
23 document . w r i t e ( ” P r i x TTC du p r o d u i t \” ”+p r o d u i t . denomination+” \” : ”+
calculPrixTTC ( p r o d u i t ) ) ;
24 </s c r i p t>
25 <p>
26 </body>
27 </html>

Dans la mesure du possible, il est préférable de définir les objets JavaScript par des littéraux
car ça peut être plus efficace que la construction dynamique avec le constructeur Object.

1.5 Tableaux (le type Array)


1.5.1 Notion d’Array et construction
Dans les langages classique, un tableau est une séquence d’éléments, contigus en mémoire, avec
un accès aux éléments par un indice entier. En JavaScript, les tableaux sont des objets dont
les propriétés sont automatiquement nommées avec les chaînes '0', '1', '2'. Ces tableaux
possèdent certains avantages des objets, comme par exemple la possibilité d’avoir des éléments
de types différents, mais sont significativement plus lents que les tableaux classiques.
Un tableau peut être créé par un littéral, entre crochets [ ].
exemples/bases/ex08_arrayLitterals.html
1 <! doctype HTML>
2 <html l a n g=” f r ”>
3 <head>
4 <meta c h a r s e t=”UTF−8” />
5 <t i t l e>Tableaux</ t i t l e>
6 </head>
7 <body>
8 <p>
9 <s c r i p t>
10 // Dé c l a r a t i o n d ’ una a r r a y s o u s forme de l i t t é r a l
11 var tab = [ 1 , 3 , ” coucou ” , 6 ] ;
12 tab [ 4 ] = 9 ; // a j o u t d ’ un é l é ment
13 for ( var i =0 ; i<tab . l e n g t h ; i ++){
14 document . w r i t e ( tab [ i ]+ ”<br />” ) ;
15 }
16 </s c r i p t>
17 <p>
18 </body>
19 </html>

Un tableau peut aussi être créé par le constructeur d’Array. Celui-ci peut prendre en argu-
ment soit le nombre de cases du tableau à allouer, soit les éléments du tableau initialisés lors

11
Rémy Malgouyres, http://malgouyres.org Programmation Web Côté Client, JS et jQuery

de la création du tableau. On peut toujours ajouter des éléments au tableau par une simple
affectation de ces éléments et la mémoire évolue automatiquement.

exemples/bases/ex09_arraysNew.html
1 <! doctype HTML>
2 <html l a n g=” f r ”>
3 <head>
4 <meta c h a r s e t=”UTF−8” />
5 <t i t l e>Tableaux</ t i t l e>
6 </head>
7 <body>
8 <p>
9 <s c r i p t>
10 var tab = new Array ( 1 , 3 , ” coucou ” , 6 ) ;
11 tab . push ( 9 ) ; // a j o u t d ’ un é l é ment
12 for ( var i =0 ; i<tab . l e n g t h ; i ++){
13 document . w r i t e ( tab [ i ]+ ”<br />” ) ;
14 }
15 </s c r i p t>
16 <p>
17 </body>
18 </html>

De même que pour les objets, il est préférable de définir les tableaux JavaScript par des
littéraux car ça peut être plus efficace que la construction dynamique avec le constructeur
Array.

1.5.2 Quelques méthodes prédéfinies sur le type Array


• Suppression du dernier élément (l’élément supprimé est retourné par la méthode) :
function array.pop();

• Suppression du premier élément (l’élément supprimé est retourné par la méthode) :


function array.shift();

• Suppression d’une partie des éléments :


function array.splice(firstElementKey, numberOfElementsToRemove);

• Ajout d’un ou plusieurs élément(s) à la fin :


function array.push(element1, element2...);

• Tri d’un tableau : function array.sort(compareFuntion);


où compareFuntion est une fonction permettant de comparer deux éléments du tableau
qui a pour prototype : function compareFuntion(a, b);
et renvoie 0 si les éléments sont égaux, un nombre négatif si a est strictement inférieur à
b, et un nombre positif si a est strictement supérieur à b.
Pour les chaînes de caractère, on peut utiliser la méthode string.localCompare(that)
(similaire à strcmp).

12
Chapitre 1 : Premiers pas en JavaScript

1.6 Exemple : traitement d’un formulaire avec jQuery


1.6.1 Qu’est-ce que jQuery ?
La librairie jQuery, dont on peut obtenir le code et la documentation sur api.jquery.com,
permet de simplifier la gestion de différents aspects d’une application côté client en JavaScript :

• Gestion des événements utilisateur ;

• Récupération des valeurs saisies dans un formulaire ;

• Manipulation du document via le DOM ;

• Requêtes asynchrones (transfert de données entre serveur et client en dehors du charge-


ment initial de la page) ;

• Codage des données pour la transfert (par exemple JSON ).

Pour utiliser jQuery, il suffit d’insérer son code dans un script, via une balise (remplacer
x.xx.x par le numéro de version utilisé sur jquery.com) :
<script src="https://code.jquery.com/jquery-x.xx.x.js"></script>
Pour travailler offline, on peut utiliser jQuery en local après téléchargement dans le répertoire
courant :
<script src="./jquery-x.xx.x.js"></script>
Les méthodes de jQuery peuvent être appelées (avec des argument args) par l’abréviation
$(args).

1.6.2 Récupérer, filtrer et afficher les données d’un formulaire


Le script suivant récupère les données d’un formulaire, les filtres par expressions régulières, et
les affiche en modifiant le DOM.
Plus précisément, le script réalise les opération suivantes :
• Déclaration d’un gestionnaire (fonction afficheDonneesForm) de l’événement submit du
formulaire ayant formStudentData pour ID ;

• Dans cette fonction afficheDonneesForm,

– Récupération des valeurs saisies dans les éléments ayant nom et annee pour ID, qui
sont respectivement un input et un select.
– Test sur la forme (expression régulière, champs obligatoire,...) sur les valeurs des
champs nom et année du formulaire (à l’aide d’un littéral de type expression régulière
entre slashes /.../).
– Ajout dans le <span> ayant spanResultat pour ID du code HTML du résultat de
la saisie (affichage du nom et de l’année, ou le cas échéant un message d’erreur).
– Empêcher le comportement par défaut de la soumission du formulaire (appel du
script action côté serveur lors du click sur l’input de type submit).

13
Rémy Malgouyres, http://malgouyres.org Programmation Web Côté Client, JS et jQuery

Voici le fichier HTML :


exemples/bases/ex10_jQueryForm.html
1 <! doctype HTML>
2 <html l a n g=” f r ”>
3 <head>
4 <meta c h a r s e t=”UTF−8” />
5 <t i t l e>F o r m u l a i r e s avec jQuery</ t i t l e>
6 </head>
7 <body>
8 <form i d=” formStudentData ”>
9 <p>
10 <l a b e l f or=”nom” >Nom</ l a b e l>
11 <i nput name=”nom” i d=”nom” />
12 </p>
13 <p>
14 <s e l e c t name=” annee ” i d=” annee ”>
15 <option v a l u e=” c h o i s i s s e z ” s e l e c t e d d i s a b l e d>−− c h o i s i s s e z −−</option>
16 <option v a l u e=” p r e m i e r e ”>Première ann é e</option>
17 <option v a l u e=” deuxième ”>Deuxième ann é e</option>
18 </s e l e c t>
19 </p>
20 <p>
21 <i nput type=” s u b m i t ” v a l u e=” V a l i d e r ” />
22 </p>
23 </form>
24
25 <p>
26 <s trong>donn é e s s a i s i e s &nbsp ; :</s trong><br />
27
28 <!−− Les r é s u l t a t s de l a s a i s i e du f o r m u l a i r e vont s ’ a f f i c h e r dans c e span
−−>
29 <span i d=” s p a n R e s u l t a t ”></span>
30 </p>
31 <s c r i p t s r c=” j q u e r y . j s ”></s c r i p t>
32 <s c r i p t s r c=” ex10_jQueryForm . j s ”></s c r i p t>
33 </body>
34 </html>

Il est recommandé de mettre, dans la mesure du possible, le script à la fin du document,


car cela limite le coût et le délai des chargements et parsing de la librairie jQuery lors d’un
premier chargement (ou rafraîchissement) de la page. Voici le fichier JavaScript :
exemples/bases/ex10_jQueryForm.js
1 // Mé t h o d e de r é cup é r a t i o n e t a f f i c h a g e d e s i n p u t s de f o r m u l a i r e
2 // à l ’ a i d e de jQuery :
3 var a f f i c h e D o n n e e s F o r m = function ( e v e n t ) {
4 // r é cup é r a t i o n ( v i a jQuery ) de l a v a l e u r de l ’ i n p u t d ’ ID ”nom”
5 var nom = $ ( ”#nom” ) . v a l ( ) ;
6 // r é cup é r a t i o n ( v i a jQuery ) de l a v a l e u r du s e l e c t d ’ ID ” annee ”
7 var annee = $ ( ”#annee ” ) . v a l ( ) ;
8
9 // t e s t de champs o b l i g a t o i r e s e t e x p r e s s i o n s r é g u l i è r e s
10 i f ( annee==” c h o i s i s s e z ” | |
11 ! /^ [ a−zA−ZÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞßàáâãäåæ ¸ è é ê ö ì í î ïðñ ò ó ôõö÷øùúûĀāüýþÿ
\ s ” ’ −]{1 ,} $/

14
Chapitre 1 : Premiers pas en JavaScript

12 . t e s t (nom) ) {
13 $ ( ”#s p a n R e s u l t a t ” ) . html ( ” Problème : forme d ’ un champs i n c o r r e c t . ” ) ;
14 } else {
15 $ ( ”#s p a n R e s u l t a t ” ) . html ( ”<em>Nom : </em>” + nom + ”<br />” +
16 ”<em>Annee : </em>” + annee ) ;
17 }
18 // É v i t e r d ’ a p p e l e r l ’ ” a c t i o n ” par d é f a u t ( ) s c r i p t PHP, e t c . . . )
19 // du f o r m u l a i r e l o r s du s u b m i t
20 event . preventDefault ( ) ;
21 };
22
23 // G e s t i o n de l ’ é v é nement s u b m i t du f o r m u l a i r e .
24 // On d é f i n i t afficheDonneesForm comme g e s t i o n n a i r e ( h a n d l e r )
25 // de l ’ é v é nement
26 $ ( ”#formStudentData ” ) . on ( ” s u b m i t ” , a f f i c h e D o n n e e s F o r m ) ;

15
Chapitre 2

Programmation Fonctionnelle et Objet


en JavaScript

On distingue en JavaScript deux catégories de patterns (et éventuellement des patterns hy-
brides) :
• Les patterns dits fonctionnels s’appuient sur les aspects de JavaScript en tant que langage
fonctionnel. Autrement dit, ces patterns exploitent les propriétés des fonctions JavaScript
en tant que données, ainsi que la portée des variables dans ces fonctions.
• Les patterns dits prototypaux s’appuient sur les aspects de JavaScript en tant que langage
prototypal. Ceci est lié à une propriété que possèdent tous les objets JavaScript, appelée
le prototype. Le prototype permet de partager des propriétés entre plusieurs objets, et
il conduit naturellement à des notions d’héritage. Il permet aussi d’augmenter les objets
pour leur rajouter des propriétés, bien après que ces objets aient été définis, y compris
sur les types de base comme String.
Nous commencerons par voir un certain nombre de patterns fonctionnels, qui permettent
de faire de la programmation objet avec des notions comme la visibilité, la structuration d’une
application en modules (ou packages), des fabriques, ou encore des patterns permettant le
découplage des composants d’une application à base d’événements, ou comme subscriber/pu-
blisher.
Ces patterns peuvent paraître déconcertant au premier abord pour un développeur habitué
aux langages objet classiques. Avec un peu d’habitude, on en vient à considérer que JavaScript
est un excellent langage objet, très expressif et très souple. Cependant, certains problèmes de
conception du langage, qui n’ont pu être corrigés pour assurer la compatibilité ascendante,
nécessitent quelques précautions, sous la forme de bonnes habitudes.

2.1 Le Pattern Module


Le pattern Module permet de créer des composants qui peuvent jour le rôle que jouent les classes
dans les langages objet classiques. Il permet, entre autre, de créer des données et méthodes
privées, et une interface publique avec d’autres données et méthodes, qui sont accessibles de
l’extérieur, et qui peuvent, elles, accéder aux propriétés privées.
Le pattern consiste à créer une fonction. Les données et méthodes privées sont simplement
des variables locales de la fonction. Elles ne sont donc pas visibles du monde extérieur à la

16
Chapitre 2 : Programmation Fonctionnelle et Objet en JavaScript

fonction. La fonction renvoie un objet, qui constitue l’interface publique du module, dont les
propriétés (données, objets ou fonctions) accèdent aux variables privées. Lorsque l’objet est
retourné, on ne peut plus accéder directement aux variables locales de la fonction, mais celles-
ci restent vivantes (leur cycle de vie ne se termine pas) tant que l’objet retourné qui s’y réfère
n’est pas lui-même détruit. Autrement dit, on peut continuer à manipuler ces variables locales
au travers des méthodes de l’interface publique.
exemples/objet/ex01_modulePattern.js
1 var mySecretModule = function ( d e f a u l t S e c r e t V a l u e ) {
2
3 // donn é e p r i v é e a v e c une v a l e u r par d é f a u t
4 var m y P r i v a t e S e c r e t = ( ( d e f a u l t S e c r e t V a l u e &&
5 typeof d e f a u l t S e c r e t V a l u e === ” s t r i n g ” )
6 && d e f a u l t S e c r e t V a l u e )
7 | | ”” ;
8
9 // Mé t h o d e p r i v é e :
10 var myRegexTestMethod = function ( c h a i n e ) {
11 return ( typeof c h a i n e === ” s t r i n g ” ) && /^ [ a−z ] * $/ i . t e s t ( c h a i n e ) ;
12 };
13
14 // On c r é e un o b j e t q u i va ê t r e rendu p u b l i c
15 // Cet o b j e t va ê t r e r e t o u r n é , mais pas l e s donn é e s p r i v é e s .
16 var p u b l i c I n t e r f a c e = {
17
18 // Les é l é ments p u b l i c s s o n t l e s p r o p r i é t é s de p u b l i c I n t e r f a c e
19
20 // Donné e p u b l i q u e :
21 donneePublique : ’ donn é e par d é f a u t ’ ,
22
23 // S e t t e r
24 s e t S e c r e t : function ( s e c r e t V a l u e ) {
25 // Test d ’ e x p r e s s i o n r é g u l i è r e
26 i f ( myRegexTestMethod ( s e c r e t V a l u e ) ) {
27 myPrivateSecret = secretValue ;
28 } else {
29 throw {
30 name : ” I l l e g a l A r g u m e n t E x c e p t i o n ” ,
31 message : ”Le s e c r e t ” + s e c r e t V a l u e + ” e s t i n v a l i d e . ”
32 };
33 }
34 },
35
36 // A c c e s s e u r :
37 g e t S e c r e t : function ( ) {
38 return m y P r i v a t e S e c r e t ;
39 },
40
41 } ; // Fin de p u b l i c I n t e r f a c e
42
43 return p u b l i c I n t e r f a c e ;
44 }

exemples/objet/ex01_modulePattern.html

17
Rémy Malgouyres, http://malgouyres.org Programmation Web Côté Client, JS et jQuery

1 /<! d o c t y p e HTML>
2 <html lang=” f r ”>
3 <head>
4 <meta charset=”UTF−8” />
5 <t i t l e>P a t t e r n ” Module ”</ t i t l e>
6
7 </head>
8 <body>
9 <p>
10 <s c r i p t src=” . /ex01_modulePattern . j s ”></s c r i p t>
11 <s c r i p t>
12 var s e c r e t M o d u l e = mySecretModule ( ” i n i t S e c r e t ” ) ;
13
14 document . w r i t e ( ” d o n n e e P u b l i q u e : ” + s e c r e t M o d u l e . donneePublique + ”<br />” ) ;
15
16 // M o d i f i c a t i o n de l a donn é e p u b l i q u e
17 s e c r e t M o d u l e . donneePublique = ” n o u v e l l e donn é e p u b l i q u e ” ;
18 document . w r i t e ( ” d o n n e e P u b l i q u e : ” + s e c r e t M o d u l e . donneePublique + ”<br />” ) ;
19
20 // A c c e s s e u r de s e c r e t :
21 document . w r i t e ( ” S e c r e t : ” + s e c r e t M o d u l e . g e t S e c r e t ( ) + ”<br />” ) ;
22
23 // T e n t a t i v e de m o d i f i e r l e s e c r e t
24 try {
25 s e c r e t M o d u l e . s e t S e c r e t ( ” a b cd e ” ) ;
26 document . w r i t e ( ” S e c r e t : ” + s e c r e t M o d u l e . g e t S e c r e t ( ) + ”<br />” ) ;
27 } catch ( e ) {
28 document . w r i t e ( ” Erreur de t y p e ” + e . name + ”<br />Message : ” + e . message +
”<br />” ) ;
29 }
30
31 try {
32 s e c r e t M o d u l e . s e t S e c r e t ( ” abcde567 ” ) ;
33 document . w r i t e ( ” S e c r e t : ” + s e c r e t M o d u l e . g e t S e c r e t ( ) + ”<br />” ) ;
34 } catch ( e ) {
35 document . w r i t e ( ” Erreur de t y p e ” + e . name + ” : ” + e . message + ”<br />” ) ;
36 }
37 </s c r i p t>
38 </p>
39 </body>
40 </html>

Lé mécanisme du langage essentiel pour ce pattern est la portée (scope) des variables locales
à une fonction, qui s’étend aux sous-fonctions de la fonction, et à leurs sous-fonctions...

18
Chapitre 2 : Programmation Fonctionnelle et Objet en JavaScript

2.2 Passage d’arguments par objets


En JavaScript, il est souvent plus pratique, plutôt que de passer une série de paramètres, ce
qui oblige à tenir compte de l’ordre de ces paramètres, de donner en argument à une fonction
les données dans les propriétés d’un objet, soit construit à la volée, soit construit auparavant.
Ce pattern offre souvent plus de souplesse que la manière classique. Dans l’exemple suivant,
la fonction génère le code HTML de l’objet passé en paramètre, sans savoir de quel type d’objet
il s’agit. On l’utilise ensuite pour afficher une adresse.
exemples/objet/ex02_affichageObjetBasic.js
1 /* *
2 * Cré ee un cha î ne de c a r a c t è r e l i s i b l e q u i r e p r é s e n t e l ’ o b j e t .
3 * On s u p p o s e que t o u t e s l e s p r o p r i é t é s de l ’ o b j e t s o n t de t y p e cha î ne ou nombre .
4 * ( e l l e s p e u v e n t ê t r e automatiquement c o n v e r t i e s en cha î ne )
5 */
6 var objectToHtmlTable = function ( s p e c ) {
7
8 var c h a i n e = ”<table><tbody>” ;
9 // Parcours d e s p r o p r i é t é s de l ’ o b j e t s p e c p a s s é en argument
10 for ( propertyName in s p e c ) {
11 // La p r o p r i é t é e s t d é f i n i e e t non v i d e .
12 // E l l e ne v i e n t pas du p r o t o t y p e de l ’ o b j e t
13 // Ce n ’ e s t pas une f o n c t i o n
14 i f ( s p e c [ propertyName ] && s p e c . hasOwnProperty ( propertyName )
15 && typeof s p e c [ propertyName ] != ” f u n c t i o n ” ) {
16 // Concat é n a t i o n à une cha î ne . Les nombres s o n t c o n v e r t i s .
17 c h a i n e += ’<tr><td s t y l e =”text −align : right ; ”><em>’ + propertyName + ” :</
em></td>” +
18 ”<td>” + s p e c [ propertyName ] + ”</td></ tr>” ;
19 }
20 };
21 c h a i n e += ”<tbody></table>” ;
22 return c h a i n e ;
23 };

exemples/objet/ex02_affichageObjetBasic.html
1 /<! d o c t y p e HTML>

19
Rémy Malgouyres, http://malgouyres.org Programmation Web Côté Client, JS et jQuery

2 <html lang=” f r ”>


3 <head>
4 <meta charset=”UTF−8” />
5 <t i t l e>A f f i c h a g e d ’ O b j e t s Géné r i q u e</ t i t l e>
6
7 </head>
8 <body>
9 <p>
10 <s c r i p t src=” . / e x 0 2 _ a f f i c h a g e O b j e t B a s i c . j s ”></s c r i p t>
11 <s c r i p t>
12 document . w r i t e ( objectToHtmlTable ( {
13 id : ”0 f 3 e a 7 5 9 b 1 ” ,
14 numeroRue : ”2 b i s ” ,
15 r u e : ”Rue de l a Paix ” ,
16 complementAdresse : ” ” ,
17 c o d e P o s t a l : ” 63000 ” ,
18 v i l l e : ” Clermont−Ferrand ” ,
19 pays : ” France ”
20 }) ) ;
21 </s c r i p t>
22 <p>
23 </body>
24 </html>

2.3 Exemple de fabrique sommaire


Dans l’exemple suivant, une fabrique, suivant un pattern module très sommaire, construit un
objet de type adresse (éventuellement partiellement rempli), en sélectionnant les propriétés que
l’objet en paramètre qui sont dans une liste.
Cet exemple est plutôt un exemple d’école et nous verrons plus loin des exemple plus
complets, les propriété de l’objet retourné manipulant des données (attributs) privées.

exemples/objet/ex03_methodLitteralParam.js
1 var f a b r i q u e A d r e s s e V e r s i o n 1 = function ( s p e c ) {
2 // O b j e t à r e t o u r n e r i n i t i a l e m e n t v i d e
3 var a d r e s s e = { } ;
4
5 var l i s t e P r o p r i e t e s = [ ” i d ” , ”numeroRue” , ” rue ” , ” complementAdresse ” ,
6 ” c o d e P o s t a l ” , ” v i l l e ” , ” pays ” ] ;
7
8 // Parcours d e s p r o p r i é t é s de l ’ o b j e t s p e c p a s s é en argument
9 for ( propertyName in s p e c ) {
10 i f ( s p e c . hasOwnProperty ( propertyName ) ) {
11 // S i l a p r o p r i é t é e x i s t e dans l e t y p e a d r e s s e :
12 i f ( l i s t e P r o p r i e t e s . indexOf ( propertyName ) >= 0 ) {
13 a d r e s s e [ propertyName ] = s p e c [ propertyName ] ;
14 } else {
15 throw {name : ” UnknownPropertyException ” ,
16 message : ” P r o p r i é t é de l ’ a d r e s s e inconnue . ” } ;
17 }
18 }
19 }
20

20
Chapitre 2 : Programmation Fonctionnelle et Objet en JavaScript

21 return a d r e s s e ;
22 };

exemples/objet/ex03_methodLitteralParam.html
1 <! doctype HTML>
2 <html l a n g=” f r ”>
3 <head>
4 <meta c h a r s e t=”UTF−8” />
5 <t i t l e>A f f i c h a g e Géné r i q u e d ’ O b j e t s</ t i t l e>
6
7 </head>
8 <body>
9 <p>
10 <s c r i p t s r c=” . / e x 0 2 _ a f f i c h a g e O b j e t B a s i c . j s ”></s c r i p t>
11 <s c r i p t s r c=” . / ex03_methodLitteralParam . j s ”></s c r i p t>
12 <s c r i p t>
13 // c r é a t i o n d ’ une i n s t a n c e
14 var a d r e s s e = f a b r i q u e A d r e s s e V e r s i o n 1 ( {
15 i d : ”0 f 3 e a 7 5 9 b 1 ” ,
16 numeroRue : ” 2 b i s ” ,
17 r u e : ”Rue de l a Paix ” ,
18 complementAdresse : ” ” ,
19 c o d e P o s t a l : ” 63000 ” ,
20 v i l l e : ” Clermont−Ferrand ” ,
21 pays : ” France ”
22 }) ;
23
24 document . w r i t e ( objectToHtmlTable ( a d r e s s e ) ) ;
25 </s c r i p t>
26 <p>
27 </body>
28 </html>

2.4 Structuration d’une application


L’un des principaux défauts de JavaScript est sa tendance à créer, parfois sans faire exprès,
des variables globales, ce qui a tendance à créer des interactions involontaires entre des parties
du code qui n’ont rien à voir, ce qui génère des bugs difficiles à débusquer...
Nous allons voir maintenant comment rédiore les nombres de variables globales de notre
programme à une seule variable, ici appelée myApp, qui contient toute notre application.
L’objet myApp, initialement, ne contient que deux méthodes :
• Une méthode addModule qui permet d’ajouter un objet quelconque (de type Objet,
Function, Array, etc.) sous la forme de propriété de l’application.

• Une méthode init, qui permet de rajouter un ensemble de propriétés prédéfinies, sans
avoir à les créer une par une.

exemples/objet/ex04_structureApplication.js
1 /* * Dé f i n i t i o n d ’ une v a r i a b l e a p p l i c a t i o n .
2 * L ’ a p p l i c a t i o n e s t i n i t i a l e m e n t v i d e e t ne comporte que l a f o n c t i o n n a l i t é

21
Rémy Malgouyres, http://malgouyres.org Programmation Web Côté Client, JS et jQuery

3 * p e r m e t t a n t d ’ a j o u t e r d e s modules .
4 * Une mé t h o d e i n i t ( ) permet d ’ i n i t i a l i s e r p l u s i e u r s modules .
5 *
6 */
7 var myApp = {
8 /* * Mé t h o d e q u i a j o u t e un module à n o t r e a p p l i c a t i o n
9 * Un module p e u t ê t r e n ’ i m p o r t e q u e l o b j e t q u i c o n t i e n t
10 * d e s donn é e s ou d e s mé t h o d e s . . .
11 * @method addModule
12 * @param {( O b j e c t | f u n c t i o n | s t r i n g | r e g e x | number ) } m o d u l e O b j e c t
13 * − un o b j e t ou v a l e u r q u e l c o n q u e à a j o u t e r à n o t r e a p p l i c a t i o n .
14 */
15 addModule : function ( moduleName , moduleObject ) {
16 i f ( typeof moduleName === ” s t r i n g ” &&
17 /^ [ a−z ] { 1 , } [ a−z0 −9\_] * $/ i . t e s t ( moduleName ) ) {
18 t h i s [ moduleName ] = moduleObject ;
19 } else {
20 throw {
21 name : ” I l l a g e a l A r g u m e n t E x c e p t i o n ” ,
22 message : ” I m p o s s i b l e de c r é e r l e s module : nom ” + moduleName
23 + ” i l l é gal ”
24 }
25 }
26 },
27
28 /* * A j o u t e t o u t e s l e s p r o p r i é t é s d ’ un o b j e t à n o t r e a p p l i c a t i o n .
29 * @method i n i t
30 * @param { O b j e c t } s p e c − o b j e t c o n t e n a n t l e s p r o p r i é t é s à a j o u t e r .
31 */
32 i n i t : function ( s p e c ) {
33 f or ( propertyName in s p e c ) {
34 i f ( s p e c . hasOwnProperty ( propertyName ) ) {
35 t h i s . addModule ( propertyName , s p e c [ propertyName ] ) ;
36 }
37 }
38 }
39 } ;
40
41 // I n i t i a l i s a t i o n de l ’ a p p l i c a t i o n a v e c un module m e t i e r
42 // m e t i e r e s t i n t ) i t i a l e m e n t v i d e .
43 myApp . i n i t ( {
44 m e t i e r : {}
45 } ) ;

Nous utilisons maintenant ce squelette d’application et nous créons dans notre application
un module metier.
Nous utilisons ensuite le pattern apply qui nous permet d’utiliser la méthode myApp.addModule
en prenant comme ”this” un autre objet que myApp.
En appliquant donc la méthode myApp.addModule en prenant myApp.metier comme ”this”,
nous créons un sous-module de myApp.metier, appelé myApp.metier.sousModule. Ce sous-
module contient une propriété essai.

exemples/objet/ex04_structureApplication.html
1 <! doctype HTML>
2 <html l a n g=” f r ”>

22
Chapitre 2 : Programmation Fonctionnelle et Objet en JavaScript

3 <head>
4 <meta c h a r s e t=”UTF−8” />
5 <t i t l e>C l a s s e s</ t i t l e>
6 <s tyl e>
7 t a b l e {border −collapse : c o l l a p s e }
8 tbody t r td , th {border −style : s o l i d ; text −align : c e n t e r ; padding : 4 pt ; }
9 </s tyl e>
10 </head>
11 <body>
12 <p>
13 <s c r i p t s r c=” e x 0 4 _ s t r u c t u r e A p p l i c a t i o n . j s ”></s c r i p t>
14 <s c r i p t>
15 // a j o u t d ’ une p r o p r i é t é au mé t i e r :
16 myApp . m e t i e r . coucou = ” t e s t ” ;
17
18 // Ajout d ’ un sous−module au module myApp . m e t i e r
19 // On a p p l i q u e ( p a t t e r n a p p l y ) addModule en p r e n a n t t h i s = myApp . m e t i e r
20 myApp . addModule . apply (myApp . m e t i e r ,
21 [ ” sousModule ” ,
22 { e s s a i : ” Je s u i s l a p r o p r i é t é \” e s s a i \” du s o u s module ” }
23 ]) ;
24
25 // Ajout d ’ une mé t h o d e mainFunction
26 myApp . addModule ( ” mainFunction ” , function ( ) {
27 document . w r i t e ( ” Fo nc ti o n myApp . mainFunction :<br />” ) ;
28 document . w r i t e ( ”myApp . m e t i e r . coucou : ” + myApp . m e t i e r . coucou + ”<br />” ) ;
29 document . w r i t e ( ”myApp . m e t i e r . sousModule . e s s a i : ” + myApp . m e t i e r . sousModule .
essai ) ;
30 }) ;
31
32 // Exé c u t i o n de l a mé t h o d e mainFunction
33 myApp . mainFunction ( ) ;
34 </s c r i p t>
35 <p>
36 </body>
37 </html>

2.5 Exemple : un module metier.regexUtil


L’exemple suivant montre l’utilisation du pattern Module pour créer un sous-module métier
utilitaire pour tester des expressions régulières courantes :

• Expressions formées avec les caractères du langage courant dans une des langues dont
les accents sont normalisés dans la norme ISO 8859 − 1 (Latin-1, Europe occidentale),
admettant aussi les guillemets, apostrophes et traits d’union (tiret haut).

• Mêmes caractère que la précédente mais admettant en outre les chiffres.

• Mêmes caractère que la précédente mais admettant en outre les caractères de ponctuation
( ; . , ! ? :) et les parenthses.

Trois expressions régulières constances (donc pré-compilées) sont définies comme données
statiques (en un seul exemplaire) privées. L’interface fournit trois méthodes pour tester ces

23
Rémy Malgouyres, http://malgouyres.org Programmation Web Côté Client, JS et jQuery

expressions régulière sur une chaîne, avec éventuellement des conditions de longueur minimale
ou maximale sur la chaîne (exemple : champs obligatoire...).

exemples/objet/ex05_modulePatternRegex.js
1 /* *
2 * A j o u t e au mé t i e r un o b j e t q u i e s t l ’ i n t e r f a c e p u b l i q u e
3 * d ’ une f o n c t i o n q u i s u i t l e ” p a t t e r n module ” .
4 * La f o n c t i o n r e t o u r n e son i n t e r f a c e p u b l i q u e q u i e s t un o b j e t .
5 * Cet o b j e t e s t a j o u t é comme sous−module au module ” m e t i e r ” .
6 *
7 * @module r e g e x U t i l
8 * @augments myApp . m e t i e r
9 */
10 myApp . addModule . apply (myApp . m e t i e r , [ ” r e g e x U t i l ” , function ( ) {
11
12 // //////////////////////////////////////////////
13 // P r o p r i é t é s e t mé t h o d e s ” s t a t i q u e s ” p r i v é e s
14
15 /* *
16 * E x p r e s s i o n r é g u l i è r e c o n s t a n t e pour l a l a n g u e n a t u r e l l e ( e t e s p a c e s )
17 * @constant
18 * @private
19 */
20 var r e g e x L a t i n 1
21 = /^ [ a−zA−ZÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞßàáâãäåæ ¸ è é ê ö ì í î ïð ñ òó ôõö÷øùúû
Āāüýþÿ \ s ” ’\ −]* $/ i ;
22
23 /* *
24 * E x p r e s s i o n r é g u l i è r e c o n s t a n t e pour l a l a n g u e n a t u r e l l e e t c h i f f r e s
25 * @constant
26 * @private
27 */
28 var r e g e x L a t i n 1 W i t h D i g i t s =
29 /^ [ a−zA−ZÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞßàáâãäåæ ¸ è é ê ö ì í î ïð ñ òó ôõö÷øùúû
Āāüýþÿ \ s ” ’\ −0 −9]* $/ i ;
30
31 /* *
32 * E x p r e s s i o n r é g u l i è r e c o n s t a n t e pour l a l a n g u e n a t u r e l l e e t c h i f f r e s ou
ponctuation
33 * @constant
34 * @private
35 */
36 var r e g e x L a t i n 1 W i t h D i g i t s P u n c t u a t i o n =
37 /^ [ a−zA−ZÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞßàáâãäåæ ¸ è é ê ö ì í î ïð ñ òó ôõö÷øùúû
Āāüýþÿ \ s ” ’\ −0 −9\ ;\.\ ,\ !\ ?\ :\(\) ] * $/ i ;
38
39 /* *
40 * V a l i d e une e x p r e s s i o n r é g u l i è r e s u r une c h a i n e ( a v e c c o n d i t i o n s de
longueur )
41 * @method v a l i d a t e R e g e x
42 * @param { O b j e c t } s p e c − o b j e t c o n t e n a n t l e s donn é e s du t e s t à e f f e c t u e r
43 * @param { f u n c t i o n } s p e c . r e g e x T e s t − f o n c t i o n de t e s t q u i r e n v o i e t r u e en
c a s de s u c c è s
44 e t un message d ’ e r r e u r en c a s d ’ é c h e c
45 * @param { s t r i n g } s p e c . c h a i n e − cha î ne de c a r a c t è r e s à t e s t e r
46 * @param {number} [ minLength =0] − l o n g u e u r minimale pour l a cha î ne

24
Chapitre 2 : Programmation Fonctionnelle et Objet en JavaScript

47 * @param {number} [ maxLength ] − l o n g u e u r maximale pour l a cha î ne ( d é f a u t :


illimit é)
48 * @return { b o o l e a n } t r u e s i l e s c o n d i s i o n s s o n t s a t i s f a i t e s , f a l s e s i n o n .
49 */
50 var v a l i d a t e R e g e x = function ( s p e c ) {
51 i f ( typeof s p e c . c h a i n e === ” s t r i n g ”
52 && ( ! s p e c . minLength | | s p e c . c h a i n e . l e n g t h >= s p e c . minLength )
53 && ( ! s p e c . maxLength | | s p e c . c h a i n e . l e n g t h <= s p e c . maxLength )
54 ){
55 return s p e c . r e g e x . t e s t ( s p e c . c h a i n e ) ;
56 }
57 return f a l s e ;
58 };
59
60 // //////////////////////////////////////////////
61 // I n t e r f a c e p u b l i q u e du module
62
63 /* *
64 * Cré a t i o n d ’ un o b j e t c o n t e n a n t l e s donn é e s e t mé t h o d e s p u b l i q u e s
65 * ( l e s p r o p r i é t é s p u b l i q u e s s o n t r e t o u r n é e s par l a f o n c t i o n ” module ”) .
66 */
67 var p u b l i c I n t e r f a c e R e g e x = {
68
69
70 /* *
71 * mé t h o d e p u b l i q u e : t e s t d ’ e x p r e s s i o n du l a n g a g e a v e c c h i f f r e s
72 * @method t e s t R e g e x L a t i n 1
73 * @param { O b j e c t } s p e c − o b j e t c o n t e n a n t l e s donn é e s du t e s t à e f f e c t u e r
74 * @param { s t r i n g } s p e c . c h a i n e − cha î ne de c a r a c t è r e s à t e s t e r
75 * @param {number} [ minLength =0] − l o n g u e u r minimale pour l a cha î ne
76 * @param {number} [ maxLength ] − l o n g u e u r maximale pour l a cha î ne
77 * @return { b o o l e a n | s t r i n g } t r u e s i l e s c o n d i s i o n s s o n t s a t i s f a i t e s , un
message d ’ e r r e u r s i n o n .
78 */
79 t e s t R e g e x L a t i n 1 : function ( s p e c ) {
80 // Ajout d ’ une p r o p r i é t é à s p e c ( a ug m e nta ti on )
81 spec . regex = regexLatin1 ;
82 return v a l i d a t e R e g e x ( s p e c ) ;
83 },
84
85 /* *
86 * mé t h o d e p u b l i q u e : t e s t d ’ e x p r e s s i o n du l a n g a g e a v e c c h i f f r e s
87 * @method t e s t R e g e x L a t i n 1 W i t h D i g i t s
88 * @param { O b j e c t } s p e c − o b j e t c o n t e n a n t l e s donn é e s du t e s t à e f f e c t u e r
89 * @param { s t r i n g } s p e c . c h a i n e − cha î ne de c a r a c t è r e s à t e s t e r
90 * @param {number} [ minLength =0] − l o n g u e u r minimale pour l a cha î ne
91 * @param {number} [ maxLength ] − l o n g u e u r maximale pour l a cha î ne
92 * @return { b o o l e a n | s t r i n g } t r u e s i l e s c o n d i s i o n s s o n t s a t i s f a i t e s , un
message d ’ e r r e u r s i n o n .
93 */
94 t e s t R e g e x L a t i n 1 W i t h D i g i t s : function ( s p e c ) {
95 // Ajout d ’ une p r o p r i é t é à s p e c ( a ug m e nta ti on )
96 spec . regex = regexLatin1WithDigits ;
97 return v a l i d a t e R e g e x ( s p e c ) ;
98 },
99

25
Rémy Malgouyres, http://malgouyres.org Programmation Web Côté Client, JS et jQuery

100 /* *
101 * mé t h o d e p u b l i q u e : t e s t d ’ e x p r e s s i o n du l a n g a g e a v e c c h i f f r e s
102 * @method t e s t R e g e x L a t i n 1 W i t h D i g i t s P u n c t u a t i o n
103 * @param { O b j e c t } s p e c − o b j e t c o n t e n a n t l e s donn é e s du t e s t à e f f e c t u e r
104 * @param { s t r i n g } s p e c . c h a i n e − cha î ne de c a r a c t è r e s à t e s t e r
105 * @param {number} [ minLength =0] − l o n g u e u r minimale pour l a cha î ne
106 * @param {number} [ maxLength ] − l o n g u e u r maximale pour l a cha î ne
107 * @return { b o o l e a n | s t r i n g } t r u e s i l e s c o n d i s i o n s s o n t s a t i s f a i t e s , un
message d ’ e r r e u r s i n o n .
108 */
109 t e s t R e g e x L a t i n 1 W i t h D i g i t s P u n c t u a t i o n : function ( s p e c ) {
110 // Ajout d ’ une p r o p r i é t é à s p e c ( a ug m e nta ti on )
111 spec . regex = regexLatin1WithDigitsPunctuation ;
112 return v a l i d a t e R e g e x ( s p e c ) ;
113 }
114
115 } ; // f i n de p u b l i c I n t e r f a c e R e g e x
116
117 // On r e t o u r n e l ’ o b j e t c o n t e n a n t l ’ i n t e r f a c e p u b l i q u e .
118 return p u b l i c I n t e r f a c e R e g e x ;
119
120 } ( ) ] // f i n ET APPEL de l a f o n c t i o n q u i c r é e l ’ o b j e t ” r e g e x U t i l ”
121
122 ) ; // f i n de l ’ a p p e l ” a p p l y ” de l a mé t h o d e myApp . addModule
123 // ( a j o u t de l ’ o b j e t p u b l i c I n t e r f a c e R e g e x au m e ti e r , s o u s l e nom r e g e x U t i l )

Le fichier HTML réalise des tests des méthodes du module regexUtil sur un jeu de chaînes,
et affiche les résultats dans une table.

exemples/objet/ex05_modulePatternRegex.html
1 /<! d o c t y p e HTML>
2 <html lang=” f r ”>
3 <head>
4 <meta charset=”UTF−8” />
5 <t i t l e>Module Regex</ t i t l e>
6 <l i nk rel=” s t y l e s h e e t ” , href=” ex05_modulePatternRegex . c s s ” />
7 </head>
8 <body>
9 <!−− Cr é a t i o n de l ’ a p p l i c a t i o n v i d e avec deux mé t h o d e s −−>
10 <s c r i p t src=” e x 0 4 _ s t r u c t u r e A p p l i c a t i o n . j s ”></s c r i p t>

26
Chapitre 2 : Programmation Fonctionnelle et Objet en JavaScript

11 <!−− Cr é a t i o n de sous−module r e g e x U t i l de myApp . m e t i e r −−>


12 <s c r i p t src=” . /ex05_modulePatternRegex . j s ”></s c r i p t>
13
14 <!−− Ajout d’un main e t ex é c u t i o n −−>
15 <s c r i p t>
16 // Ajout d ’ u n e mé t h o d e mainFunction
17 myApp . addModule ( ” mainFunction ” , function ( ) {
18 // Cha î nes pour l e s t e s t s d ’ e x p r e s s i o n s r é g u l i è r e s :
19 var ta bC ha in e s = [ ” L’ é norme Bla−bl à” , ” B l a b l a 2 ” , ” B l a b l a#” , ” a u t r e b l a b l a
: b l i ( bleu )” ];
20 var i ;
21 // R a c c o u r c i par c o p i e de r é f é r e n c e :
22 var r e g e x U t i l = myApp . m e t i e r . r e g e x U t i l ;
23 var t e x t e = ”<table><thead>” +
24 ”<tr><th></th><th>L a t i n 1</th><th>L a t i n 1 w i t h D i g i t s</th>” +
25 ”<th>L a t i n 1 w i t h D i g i t s<br />and p unc t</th></ tr></thead><tbody>”
;
26 for ( i = 0 ; i< tabC ha i n e s . l e n g t h ; i ++){
27 t e x t e += ”<tr><td>” + t ab Ch ai ne s [ i ] + ”</td>”
28 + ”<td>” + r e g e x U t i l . t e s t R e g e x L a t i n 1 ( {
29 c h a i n e : t ab Ch ai ne s [ i ]
30 } ) + ”</td>”
31 + ”<td>” + r e g e x U t i l . t e s t R e g e x L a t i n 1 W i t h D i g i t s ( {
32 c h a i n e : t ab Ch ai ne s [ i ]
33 } ) + ”</td>”
34 + ”<td>” + r e g e x U t i l . t e s t R e g e x L a t i n 1 W i t h D i g i t s P u n c t u a t i o n ( {
35 c h a i n e : t ab Ch ai ne s [ i ]
36 } ) + ”</td>”
37 }
38 t e x t e += ”</tbody></table>” ;
39
40 document . w r i t e ( t e x t e ) ;
41 } ) ; // f i n de myApp . addModule (” mainFunction ”
42
43 // Lancement de l ’ a p p l i c a t i o n :
44 myApp . mainFunction ( ) ;
45 </s c r i p t>
46 </body>
47 </html>

2.6 Module Métier adresse


Nous créons maintenant un sous-module myApp.metier.adresse. Celui-ci comporte une par-
tie privée, avec notamment une donnée membre statique propertiesPatterns, qui définit la
structure d’une adresse. Ici, propertiesPatterns définit, pour chaque propriété, une méthode
de test par expression régulière de validité de la valeur, et une propriété labelText à afficher
pour indiquer à l’utilisateur de quelle propriété il s’agit (typiquement : texte de label associé
à un input dans un formulaire). On pourrait facilement adapter le code pour permettre des
propriétés calculées.
L’interface propose quelques méthodes statiques utilitaires, comme l’accès à la liste des
noms de propriétés, aux sonnées labelText, ou le test d’expression régulière d’une propriété.
exemples/objet/ex06_moduleMetierAdresse.js

27
Rémy Malgouyres, http://malgouyres.org Programmation Web Côté Client, JS et jQuery

1 /* *
2 * Dé f i n i t l e s p r o p r i é t é s g éné r a l e d e s o b j e t s mé t i e r s r e p r é s e n t a n t d e s a d r e s s e s .
3 * On a j o u t e au mé t i e r un o b j e t q u i e s t l ’ i n t e r f a c e p u b l i q u e d ’ une f o n c t i o n q u i
s u i t l e p a t t e r n ” module ” .
4 * La f o n c t i o n r e t o u r n e son i n t e r f a c e p u b l i q u e q u i e s t un o b j e t .
5 * Cet o b j e t e s t a j o u t é comme sous−module au module ” m e t i e r ” .
6 *
7 * Dans c e t o b j e t , on ne t r o u v e pas pour l e moment l e s p r o p r i é t é s d ’ i n s t a n c e .
C e l l e s −c i s e r o n t a j o u t é e s par ” au g m enta tio n ” .
8 *
9 * @module a d r e s s e
10 * @augments myApp . m e t i e r
11 */
12 myApp . addModule . apply (myApp . m e t i e r , [ ” a d r e s s e ” , function ( ) {
13
14 // R a c c o u r c i ( a l i a s ) v e r s l e module de r e g e x
15 var r e g e x U t i l = myApp . m e t i e r . r e g e x U t i l ;
16
17 // //////////////////////////////////////////////
18 // P r o p r i é t é s e t mé t h o d e s ” s t a t i q u e s ” p r i v é e s
19
20 /* *
21 * Dé f i n i t l a s t r u c t u r e d e s o b j e t s de t y p e a d r e s s e :
22 * p r o p r i é t é s a t t e n d u e s , forme de c e s donn é e s . . .
23 *
24 * @constant
25 * @private
26 *
27 *
@property { O b j e c t } i d − P r o p r i é t é s de l ’ i d e n t i f i a n t u n i q u e de l ’ i n s t a n c e
28 *
@property { O b j e c t } numé roRue − P r o p r i é t é s du numé ro de l a rue
29 *
@property { O b j e c t } rue − P r o p r i é t é s du nom de l a rue / p l a c e
30 *
@property { O b j e c t } complementAdresse − P r o p r i é t é s du compl é ment Lieu d i t /
Bâ t i m e n t . . .
31 * @property { O b j e c t } c o d e P o s t a l − P r o p r i é t é s du code p o s t a l
32 * @property { O b j e c t } v i l l e − P r o p r i é t é s du nom de l a v i l l e
33 * @property { O b j e c t } numé roRue − P r o p r i é t é s du nom du pays
34 */
35 var p r o p e r t i e s P a t t e r n s = {
36 id : {
37 r e g e x T e s t : function ( c h a i n e ) {
38 i f ( /^[0−9a−f ] { 1 0 } $/ i . t e s t ( c h a i n e ) === true ) {
39 return true ;
40 } else {
41 return ”L ’ i d e n t i f i a n t d o i t comporter 10 c h i f f r e s hexa . ” ;
42 }
43 },
44 labelText : ” I d e n t i f i a n t ”
45 },
46 numeroRue : {
47 r e g e x T e s t : function ( c h a i n e ) {
48 i f ( r e g e x U t i l . testRegexLatin1WithDigits ({
49 chaine : chaine ,
50 maxLength : 15
51 } ) === true )
52 {
53 return true ;

28
Chapitre 2 : Programmation Fonctionnelle et Objet en JavaScript

54 } else {
55 return ”Le numé ro de l a rue c o n t i e n t au p l u s 15 c a r a c t è r e s , ”
56 +” l e t t r e s , t i r e t s e t g u i l l e m e t s ou c h i f f r e s . ” ;
57 }
58 },
59 l a b e l T e x t : ”Numé ro ”
60 },
61 rue : {
62 r e g e x T e s t : function ( c h a i n e ) {
63 i f ( r e g e x U t i l . testRegexLatin1WithDigits ({
64 chaine : chaine ,
65 minLength : 1 ,
66 maxLength : 255
67 } ) === true )
68 {
69 return true ;
70 } else {
71 return ” l e nom de l a rue / p l a c e , o b l i g a t o i r e ne c o n t i e n t que ”
72 + ” d e s l e t t r e s , t i r e t s e t g u i l l e m e t s ou c h i f f r e s . ” ;
73 }
74 },
75 l a b e l T e x t : ” rue / p l a c e ”
76 },
77 complementAdresse : {
78 r e g e x T e s t : function ( c h a i n e ) {
79 i f ( r e g e x U t i l . testRegexLatin1WithDigitsPunctuation ({
80 chaine : chaine ,
81 maxLength : 255
82 } ) === true )
83 {
84 return true ;
85 } else {
86 return ” l e compl é ment d ’ a d r e s s e ne c o n t i e n t que d e s l e t t r e s , ”
87 + ” t i r e t s e t g u i l l e m e t s ou c h i f f r e s . ” ;
88 }
89 },
90 l a b e l T e x t : ” Lieu d i t , Bâ timent , BP”
91 },
92 codePostal : {
93 r e g e x T e s t : function ( c h a i n e ) {
94 i f ( /^ [0 −9]{5} $/ . t e s t ( c h a i n e ) === true ) {
95 return true ;
96 } else {
97 return ”Le code p o s t a l d o i t comporter 5 c h i f f r e s d é cimaux . ” ;
98 }
99 },
100 l a b e l T e x t : ”Code P o s t a l ”
101 },
102 ville : {
103 r e g e x T e s t : function ( c h a i n e ) {
104 i f ( r e g e x U t i l . testRegexLatin1 ({
105 chaine : chaine ,
106 minLength : 1 ,
107 maxLength : 255
108 } ) === true )
109 {

29
Rémy Malgouyres, http://malgouyres.org Programmation Web Côté Client, JS et jQuery

110 return true ;


111 } else {
112 return ”La v i l l e , o b l i g a t o i r e , ne c o n t i e n t que d e s l e t t r e s , ”
113 + ” t i r e t s et guillemets . ” ;
114 }
115 },
116 labelText : ” Ville ”
117 },
118 pays : {
119 r e g e x T e s t : function ( c h a i n e ) {
120 i f ( r e g e x U t i l . testRegexLatin1 ({
121 chaine : chaine ,
122 minLength : 1 ,
123 maxLength : 255
124 } ) === true )
125 {
126 return true ;
127 } else {
128 return ”Le pays , o b l i g a t o i r e , ne c o n t i e n t que d e s l e t t r e s , ”
129 + ” t i r e t s et guillemets . ” ;
130 }
131 },
132 l a b e l T e x t : ” Pays ”
133 }
134 } ; // f i n de l ’ o b j e t p r o p e r t i e s P a t t e r n s
135
136 /* *
137 * Tableau c o n t e n a n t l a l i s t e d e s p r o p r i é t é s a t t e n d u e s d ’ une i n s t a n c e d ’
a d r e s s e . Le t a b l e a u e s t pr é c a l c u l é l o r s de l ’ i n i t i a l i s a t i o n .
138 * @member
139 * @private
140 */
141 var p r o p e r t y L i s t = function ( ) {
142 var l i s t e = [ ] ;
143
144 // Parcours d e s p r o p r i é t é s de l ’ o b j e t p r o p e r t i e s P a t t e r n s . r e g e x T e s t
145 // q u i c o r r e s p o n d e n t aux p r o p r i é t é s de l ’ a d r e s s e
146 for ( var propertyName in p r o p e r t i e s P a t t e r n s ) {
147 // Ne p a s c o n s i d é r e r l e s p r o p r i é t é s ” h é r i t é e s ” du p r o t o t y p e .
148 i f ( p r o p e r t i e s P a t t e r n s . hasOwnProperty ( propertyName ) ) {
149 l i s t e . push ( propertyName ) ;
150 }
151 }
152
153 return l i s t e ;
154 } ( ) ; // a p p e l immé d i a t de l a f o n c t i o n anonyme .
155
156
157 // //////////////////////////////////////////////
158 // I n t e r f a c e p u b l i q u e du module
159
160 /* *
161 * Cré a t i o n d ’ un o b j e t c o n t e n a n t l e s donn é e s e t mé t h o d e s p u b l i q u e s
162 * ( l e s p r o p r i é t é s p u b l i q u e s s o n t r e t o u r n é e s par l a f o n c t i o n ” module ”) .
163 */
164 var p u b l i c I n t e r f a c e A d r e s s e = {

30
Chapitre 2 : Programmation Fonctionnelle et Objet en JavaScript

165
166 /* *
167 * Renvoie l a l i s t e d e s p r o p r i é t é s a t t e n d u e s d e s i n s t a n c e s d ’ a d r e s s e .
168 * @method g e t P r o p e r t y L i s t
169 */
170 g e t P r o p e r t y L i s t : function ( ) {
171 return p r o p e r t y L i s t ;
172 },
173
174 /* *
175 * Renvoie l e t e x t e de d e s c r i p t i o n de l a p r o p r i é t é a t t e n d u e d e s i n s t a n c e s d ’
adresse .
176 * Renvoie u n d e f i n e d en c a s d ’ e r r e u r ( p r o p r i é t é inconnue )
177 * @method g e t L a b e l T e x t
178 * @param { s t r i n g } propertyName − nom de p r o p r i é t é
179 * @return { s t r i n g } l e t e x t e de d e s c r i p t i o n c o u r t e du champs
180 */
181 g e t L a b e l T e x t : function ( propertyName ) {
182 return p r o p e r t i e s P a t t e r n s [ propertyName ] . l a b e l T e x t ;
183 },
184
185
186 /* *
187 * Expose l e t e s t d ’ e x p r e s s i o n r é g u l i è r e d e s p r o p r i é t é s a t t e n d u e s d e s
instances d ’ adresse .
188 * Peut ê t r e u t i l i s é e pour l e f i l t r a g e d e s donn é e s d ’ un f o r m u l a i r e .
189 * @method t e s t R e g e x
190 * @param { s t r i n g } propertyName − nom de p r o p r i é t é
191 * @param { s t r i n g } v a l u e − v a l e u r pour i n i t i a l i s e r l a p r o p r i é t é
192 * @return { b o o l e a n | s t r i n g } t r u e s i l a c h a i n e e s t un code p o s t a l v a l i d e , un
message d ’ e r r e u r s i n o n .
193 */
194 t e s t R e g e x : function ( propertyName , v a l u e ) {
195 i f ( p r o p e r t i e s P a t t e r n s [ propertyName ] === u n d e f i n e d ) {
196 return ”La p r o p r i é t é ” + propertyName + ” n ’ e x i s t e pas ” ;
197 } else {
198 return p r o p e r t i e s P a t t e r n s [ propertyName ] . r e g e x T e s t ( v a l u e ) ;
199 }
200 }
201
202 } ; // f i n de l ’ o b j e t p u b l i c I n t e r f a c e A d r e s s e
203
204 return p u b l i c I n t e r f a c e A d r e s s e ;
205
206 } ( ) ] // f i n ET APPEL de l a f o n c t i o n q u i c r é e l ’ o b j e t ” p u b l i c I n t e r f a c e A d r e s s e ”
207
208 ) ; // f i n de l ’ a p p e l ” a p p l y ” de l a mé t h o d e myApp . addModule
209 // ( a j o u t de l ’ o b j e t p u b l i c I n t e r f a c e A d r e s s e au me t i e r , s o u s l e nom a d r e s s e )

Nous créons ensuite, via un pattern Module, une fabrique d’instances d’adresse. Celle-ci
prend comme paramètre un objet contenant des valeurs pour initialiser les propriétés, effectue
les tests d’expressions régulières, et crée deux objets privés. Le premier objet, appelé adresse,
contient les propriétés de l’objet adresse. Le deuxième objet, appelé dataError, contient, pour
chaque propriété pour laquelle une erreur a été détectée au filtrage, un message d’erreur.
Des méthodes publiques, dans l’interface du module, permettent d’accéder à, ou de modifier

31
Rémy Malgouyres, http://malgouyres.org Programmation Web Côté Client, JS et jQuery

les données de l’instance.

exemples/objet/ex06_fabriqueAdresse.js
1 /* *
2 * Fabrique qui cr é e des o b j e t s repr é sentant des adresse , suiva nt l e ” pattern
module ” .
3 * Le paramètre s p e c de n o t r e f o n c t i o n e s t un o b j e t c o n t e n a n t l e s p r o p r i é t é s d ’
une a d r e s s e à c r é e r .
4 *
5 * @method c r e a t e I n s t a n c e
6 * @augments myApp . m e t i e r . a d r e s s e
7 * @param { O b j e c t } i n p u t O b j − sp é c i f i c a t i o n d e s p r o p r i é t é s d ’ une i n s t a n c e d ’
adresse
8 * @param { s t r i n g } i n p u t O b j . i d − i d e n t i f i a n t u n i q u e de l ’ i n s t a n c e
9 * @param { s t r i n g } i n p u t O b j . numeroRue − numero de rue
10 * @param { s t r i n g } i n p u t O b j . rue − nom de rue
11 * @param { s t r i n g } i n p u t O b j . complementAdresse − compl é ment d ’ a d r e s s e ( l i e u dut ,
b â timent , r é s i d e n c e , e t c . )
12 * @param { s t r i n g } i n p u t O b j . c o d e P o s t a l − code p o s t a l
13 * @param { s t r i n g } i n p u t O b j . v i l l e − nom de v i l l e
14 * @param { s t r i n g } i n p u t O b j . pays − nom de pays
15 */
16 myApp . addModule . apply (myApp . m e t i e r . a d r e s s e , [ ” c r e a t e I n s t a n c e ” , function ( inputObj
){
17
18 // //////////////////////////////////////////////
19 // P r o p r i é t é s e t mé t h o d e s ” s t a t i q u e s ” p r i v é e s
20
21 /* *
22 * O b j e t p r i v é c o n t e n a n t l e s p r o p r i é t é s de l ’ i n s t a n c e , i n i t i a l e m e n t v i d e
23 * @member
24 * @private
25 */
26 var a d r e s s e = { } ;
27 /* *
28 * O b j e t p r i v é c o n t e n a n t l e s messages d ’ e r r e u r a s s o c i é s aux p r o p r i é t é s
attendues des i n s t a n c e s .
29 * @member
30 * @private
31 */
32 var d a t a E r r o r = f a l s e ;
33
34 /* *
35 * A j o u t e une p r o p r i é t é ( message d ’ e r r e u r ) dans d a t a E r r o r
36 * @method addError
37 * @private
38 */
39 var addError = function ( propertyName , message ) {
40 // s i d a t a E r r o r n ’ e x i s t e pas , on l e c r é e
41 i f ( d a t a E r r o r === f a l s e ) {
42 dataError = {} ;
43 }
44 // Ajout d ’ une p r o p r i é t é
45 d a t a E r r o r [ propertyName ] = message ;
46 }
47

32
Chapitre 2 : Programmation Fonctionnelle et Objet en JavaScript

48 /* *
49 * S e t t e r : i n i t i a l i s e l a v a l e u r pour une p r o p r i é t é a t t e n d u e s d ’ une i n s t a n c e .
50 * En c a s d ’ e r r e u r un message pour c e t t e p r o p r i é t é e s t e s t a j o u t é dans
dataError .
51 * En l ’ a b s e n c e d ’ e r r e u r , une é v e n t u e l l e e r r e u r pr é c é d e n t e e s t e f f a c é e .
52 * @method addError
53 * @private
54 */
55 var s e t P r o p e r t y O r E r r o r = function ( propertyName , v a l u e ) {
56 var r e s u l t T e s t R e g e x = myApp . m e t i e r . a d r e s s e . t e s t R e g e x ( propertyName , v a l u e ) ;
57 // On i n t i a l i s e l a p r o p r i é t é de l ’ a d r e s s e
58 a d r e s s e [ propertyName ] = v a l u e ;
59 // S i l a v a l i d a t i o n par e x p r e s s i o n r é g u l i è r e e s t p a s s é e
60 i f ( r e s u l t T e s t R e g e x === true ) {
61 // On e f f a c e une v i e i l l e e r r e u r é v e n t u e l l e
62 delete d a t a E r r o r [ propertyName ] ;
63 } else {
64 // On i n i t a l i s e l a p r o p r i é t é de l ’ o b j e t d e s e r r e u r s .
65 // a v e c l e message d ’ e r r e u r .
66 addError ( propertyName , ” P r o p r i é t é ” + v a l u e +
67 ” i n v a l i d e : ” + resultTestRegex ) ;
68 }
69 }
70
71 // Parcours d e s p r o p r i é t é s de g e t P r o p e r t y L i s t ( )
72 // q u i c o r r e s p o n d e n t aux p r o p r i é t é s de l ’ a d r e s s e à c r é e r
73 for ( var i =0 ; i<th i s . g e t P r o p e r t y L i s t ( ) . l e n g t h ; ++i ) {
74 var propertyName = t h i s . g e t P r o p e r t y L i s t ( ) [ i ] ;
75 s e t P r o p e r t y O r E r r o r ( propertyName , inputObj [ propertyName ] ) ;
76 }
77
78 // //////////////////////////////////////////////
79 // I n t e r f a c e p u b l i q u e du module
80
81 /* *
82 * Cré a t i o n d ’ un o b j e t c o n t e n a n t l e s donn é e s e t mé t h o d e s p u b l i q u e s
83 * ( l e s p r o p r i é t é s p u b l i q u e s s o n t r e t o u r n é e s par l a f o n c t i o n ” module ”) .
84 */
85 var p u b l i c I n t e r f a c e I n s t a n c e = {
86
87 /* *
88 * Retourne l e module a v e c l e s mé t h o d e s ” s t a t i q u e s ”
89 * (comme l ’ a c c è s d i r e c t à l a l i s t e d e s p r o p r i é t é s ou l e s t e s t s r e g e x )
90 * @return { O b j e c t } l e module myApp . m e t i e r . a d r e s s e
91 */
92 getModule : function ( ) {
93 return myApp . m e t i e r . a d r e s s e ;
94 },
95
96 /* *
97 * A c c e s s e u r pour t o u s l e s membres p r i v é s d ’ i n s t a n c e .
98 * @param { s t r i n g } propertyName − nom de l a p r o p r i é t é a t t e n d u e d ’ une
instance
99 * @return { s t r i n g } l a v a l e u r de l a p r o p r i é t é ou u n d e f i n e d en c a s de nom de
p r o p r i é t é inconnu .
100 */

33
Rémy Malgouyres, http://malgouyres.org Programmation Web Côté Client, JS et jQuery

101 g e t P r o p e r t y : function ( propertyName ) {


102 return a d r e s s e [ propertyName ] ;
103 },
104
105 /* *
106 * S e t t e r : i n i t i a l i s e l a v a l e u r pour une p r o p r i é t é a t t e n d u e s d ’ une i n s t a n c e
a p r è s un t e s t .
107 * En c a s d ’ e r r e u r , un message pour c e t t e p r o p r i é t é e s t e s t a j o u t é dans
dataError .
108 * En l ’ a b s e n c e d ’ e r r e u r , une é v e n t u e l l e e r r e u r pr é c é d e n t e e s t e f f a c é e .
109 * @param { s t r i n g } propertyName − nom de l a p r o p r i é t é a t t e n d u e d ’ une
instance
110 * @param { s t r i n g } v a l u e − v a l e u r à p r e n d r e pour l a p r o p r i é t é a t t e n d u d ’ une
instance
111 * @return { b o o l e a n } t r u e s ’ i l y a au moins une e r r e u r , f a l s e s i n o n
112 */
113 setProperty : setPropertyOrError ,
114
115 /* *
116 * @return { b o o l e a n } t r u e s ’ i l y a ( au moins ) une e r r e u r , f a l s e s i n o n
117 */
118 h a s E r r o r : function ( ) {
119 i f ( d a t a E r r o r === f a l s e ) {
120 return f a l s e ;
121 }
122 for ( var propertyName in d a t a E r r o r ) {
123 i f ( d a t a E r r o r . hasOwnProperty ( propertyName ) ) {
124 return true ;
125 }
126 }
127 return f a l s e ;
128 },
129
130 /* *
131 * Donne l ’ a c c è s aux d i f f é r e n t s messages d ’ e r r e u r .
132 * @param { s t r i n g } propertyName − nom de p r o p r i é t é d ’ une i n s t a n c e d ’ a d r e s s e
133 * @return { s t r i n g | u n d e f i n e d } l e message d ’ e r r e u r pour une p r o p r i é t é s ’ i l
e x i s t e ou u n d e f i n e d en l ’ a b s e n c e d ’ e r r e u r
134 */
135 g e t E r r o r M e s s a g e : function ( propertyName ) {
136 return d a t a E r r o r [ propertyName ] ;
137 },
138
139 /* *
140 * Ré c u p è r e l a l i s t e d e s champs q u i ont une e r r e u r
141 * @return { s t r i n g [ ] } t a b l e a u d e s noms de p r o r p i é t é s q u i comportent une
erreur .
142 */
143 g e t E r r o r L i s t : function ( ) {
144 var e r r o r L i s t = [ ] ;
145 for ( var propertyName in d a t a E r r o r ) {
146 i f ( d a t a E r r o r . hasOwnProperty ( propertyName ) ) {
147 e r r o r L i s t . push ( propertyName ) ;
148 }
149 }
150 return e r r o r L i s t ;

34
Chapitre 2 : Programmation Fonctionnelle et Objet en JavaScript

151 }
152
153 } ; // f i n de p u b l i c I n t e r f a c e I n s t a n c e
154
155 return p u b l i c I n t e r f a c e I n s t a n c e ;
156
157 } // f i n de l a mé t h o d e c r e a t e I n s t a n c e
158 ] ) ; // f i n de l ’ a p p e l ” a p p l y ” de l a mé t h o d e myApp . addModule

Le fichier HTML réalise le test de création d’une instance et d’utilisation de setters, et


affiche les données et les erreurs obtenues.

exemples/objet/ex06_moduleMetierAdresse.html
1 /<! d o c t y p e HTML>
2 <html lang=” f r ”>
3 <head>
4 <meta charset=”UTF−8” />
5 <t i t l e>Cr é a t i o n d ’ I n s t a n c e s d ’ A d r e s s e s</ t i t l e>
6 <l i nk rel=” s t y l e s h e e t ” , href=” ex06_moduleMetierAdresse . c s s ” />
7 </head>
8 <body>
9 <!−− Cr é a t i o n de l ’ a p p l i c a t i o n v i d e avec deux mé t h o d e s −−>
10 <s c r i p t src=” e x 0 4 _ s t r u c t u r e A p p l i c a t i o n . j s ”></s c r i p t>
11 <!−− Cr é a t i o n de sous−module r e g e x U t i l de myApp . m e t i e r −−>
12 <s c r i p t src=” . /ex05_modulePatternRegex . j s ”></s c r i p t>
13 <!−− Cr é a t i o n de sous−module a d r e s s e de myApp . m e t i e r −−>
14 <s c r i p t src=” . /ex06_moduleMetierAdresse . j s ”></s c r i p t>
15 <!−− Cr é a t i o n d ’ u n e mé thode f a b r i q u e d ’ a d r e s s e de myApp . m e t i e r . a d r e s s e −−>
16 <s c r i p t src=” . / e x 0 6 _ f a b r i q u e A d r e s s e . j s ”></s c r i p t>
17
18 <!−− Ajout d’un main e t ex é c u t i o n −−>
19 <s c r i p t>
20

35
Rémy Malgouyres, http://malgouyres.org Programmation Web Côté Client, JS et jQuery

21 var t e s t A f f i c h e A d r e s s e = function ( a d r e s s e ) {
22 document . w r i t e ( ”<div>” ) ;
23 document . w r i t e ( ”<span><h2>Donné e s :</h2>” +
24 ”<s trong>” + myApp . m e t i e r . a d r e s s e . g e t L a b e l T e x t ( ’ i d ’ ) +
25 ” :</s trong>” + a d r e s s e . g e t P r o p e r t y ( ’ i d ’ ) + ”<br />” +
26 ”<s trong>” + myApp . m e t i e r . a d r e s s e . g e t L a b e l T e x t ( ’numeroRue’ ) +
27 ” :</s trong> ” + a d r e s s e . g e t P r o p e r t y ( ’numeroRue’ ) + ”<br />” +
28 ”<s trong>” + myApp . m e t i e r . a d r e s s e . g e t L a b e l T e x t ( ’ r u e ’ ) +
29 ” :</s trong> ” + a d r e s s e . g e t P r o p e r t y ( ’ r u e ’ ) + ”<br />” +
30 ”<s trong>” + myApp . m e t i e r . a d r e s s e . g e t L a b e l T e x t ( ’ c o m p l e m e n t A d r e s s e ’ ) +
31 ” :</s trong> ” + a d r e s s e . g e t P r o p e r t y ( ’ c o m p l e m e n t A d r e s s e ’ ) + ”<br />” +
32 ”<s trong>” + myApp . m e t i e r . a d r e s s e . g e t L a b e l T e x t ( ’ c o d e P o s t a l ’ ) +
33 ” :</s trong> ” + a d r e s s e . g e t P r o p e r t y ( ’ c o d e P o s t a l ’ ) + ”<br />” +
34 ”<s trong>” + myApp . m e t i e r . a d r e s s e . g e t L a b e l T e x t ( ’ v i l l e ’ ) +
35 ” :</s trong> ” + a d r e s s e . g e t P r o p e r t y ( ’ v i l l e ’ ) + ”<br />” +
36 ”<s trong>” + myApp . m e t i e r . a d r e s s e . g e t L a b e l T e x t ( ’ p a y s ’ ) +
37 ” :</s trong> ” + a d r e s s e . g e t P r o p e r t y ( ’ p a y s ’ ) +
38 ”</span>” ) ;
39
40 // v a r i a n t e en énumé r a n t automatiquement l e s p r o p r i é t é s
41 var htmlCode = ”<span><h2>E r r e u r s :</h2>” ;
42 for ( var i=0 ; i < myApp . m e t i e r . a d r e s s e . g e t P r o p e r t y L i s t ( ) . l e n g t h ; ++i ) {
43 var propertyName = myApp . m e t i e r . a d r e s s e . g e t P r o p e r t y L i s t ( ) [ i ] ;
44 htmlCode += ”<s trong>” + myApp . m e t i e r . a d r e s s e . g e t L a b e l T e x t ( propertyName )
+ ” :</s trong> ” +
45 a d r e s s e . g e t E r r o r M e s s a g e ( propertyName ) + ”<br />” ;
46 }
47
48 htmlCode += ”</span>” ;
49 document . w r i t e ( htmlCode ) ;
50 document . w r i t e ( ”</div>” ) ;
51 };
52
53 // Ajout d ’ u n e mé t h o d e mainFunction
54 myApp . addModule ( ” mainFunction ” , function ( ) {
55 // c r é a t i o n d ’ u n e i n s t a n c e
56 var a d r e s s e = myApp . m e t i e r . a d r e s s e . c r e a t e I n s t a n c e ( {
57 id : ” 04 a b f 8 5 b c 9 ” ,
58 numeroRue : ”2 b i s ” ,
59 r u e : ”Rue de l ’ a Paix ” ,
60 // o u b l i du champs complementAdresse
61 c o d e P o s t a l : ” 630000 ” ,
62 v i l l e : ” Clermont−Ferrand ” ,
63 pays : ” France 2”
64 }) ;
65
66 testAfficheAdresse ( adresse ) ;
67
68 a d r e s s e . s e t P r o p e r t y ( ” complementAdresse ” , ” \ ”Bâ t i m e n t 3D\ ” ” ) ;
69 a d r e s s e . s e t P r o p e r t y ( ” c o d e P o s t a l ” , ” 63000 ” ) ;
70 a d r e s s e . s e t P r o p e r t y ( ” pays ” , ” France ” ) ;
71 a d r e s s e . s e t P r o p e r t y ( ”numeroRue” , ”@#*m” ) ;
72
73 testAfficheAdresse ( adresse ) ;
74 }) ;
75

36
Chapitre 2 : Programmation Fonctionnelle et Objet en JavaScript

76 // Exé c u t i o n de l a mé t h o d e mainFunction
77 myApp . mainFunction ( ) ;
78 </s c r i p t>
79 </body>
80 </html>

2.7 Création d’un Module myApp.view.adresse


Nous ajoutons, dans un module myApp.view.adresse, des méthodes pour générer le code
HTML d’une adresse, au format compact (sur une ligne) ou au format développé (avec le
détail des labels des attribut). Nous ajoutons enfin une méthode pour générer le code d’un
formulaire d’adresse, avec affichage des erreurs sur la forme des champs saisis.

exemples/objet/ex07_adresseView.js
1 // Cré a t i o n d ’ un module myApp . v i e w e t d ’ un sous−module myApp . v i e w . a d r e s s e
2 myApp . addModule ( ” v i e w ” , { a d r e s s e : { } } ) ;
3
4 /* *
5 * Mé t h o d e de g éné r a t i o n de code HTML pour une i n s t a n c e d ’ a d r e s s e .
6 * Pour chaque p r o p r i é t é a t t e n d u e d ’ une a d r e s s e , l a d e s c r i p t i o n de l a p r o p r i é t é
e t sa v a l e u r s o n t a f f i c h é e s .
7 *
8 * @method g e t H t m l D e v e l o p p e d
9 * @augments myApp . v i e w . a d r e s s e
10 * @param { O b j e c t } a d r e s s e − sp é c i f i c a t i o n d e s p r o p r i é t é s d ’ une i n s t a n c e d ’
adresse
11 * @param { s t r i n g } a d r e s s e . i d − i d e n t i f i a n t u n i q u e de l ’ i n s t a n c e
12 * @param { s t r i n g } a d r e s s e . numeroRue − numero de rue
13 * @param { s t r i n g } a d r e s s e . rue − nom de rue
14 * @param { s t r i n g } a d r e s s e . complementAdresse − compl é ment d ’ a d r e s s e ( l i e u dut , b
â timent , r é s i d e n c e , e t c . )
15 * @param { s t r i n g } a d r e s s e . c o d e P o s t a l − code p o s t a l
16 * @param { s t r i n g } a d r e s s e . v i l l e − nom de v i l l e
17 * @param { s t r i n g } a d r e s s e . pays − nom de pays
18 */
19 myApp . addModule . apply (myApp . view . a d r e s s e , [ ” g e t H t m l D e v e l o p p e d ” , function ( a d r e s s e
){
20 var htmlCode = ” ” ;
21
22 var moduleAdresse =myApp . m e t i e r . a d r e s s e ;
23
24 i f ( a d r e s s e . g e t P r o p e r t y ( ’ numeroRue ’ ) ) {
25 htmlCode += ”<span c l a s s =\” a d r e s s e I t e m \”>” + moduleAdresse . g e t L a b e l T e x t ( ’
numeroRue ’ ) + ”&nbsp ; :</span> ” +
26 a d r e s s e . g e t P r o p e r t y ( ’ numeroRue ’ ) + ” ,<br />” ;
27 }
28
29 htmlCode += ”<span c l a s s =\” a d r e s s e I t e m \”>” + moduleAdresse . g e t L a b e l T e x t ( ’ rue ’ )
+ ”&nbsp ; :</span> ” +
30 a d r e s s e . g e t P r o p e r t y ( ’ rue ’ ) + ” ,<br />” ;
31
32 i f ( typeof a d r e s s e . g e t P r o p e r t y ( ’ complementAdresse ’ ) === ” s t r i n g ” &&
33 a d r e s s e . g e t P r o p e r t y ( ’ complementAdresse ’ ) !== ” ” ) {

37
Rémy Malgouyres, http://malgouyres.org Programmation Web Côté Client, JS et jQuery

34 htmlCode += ”<span c l a s s =\” a d r e s s e I t e m \”>” + moduleAdresse . g e t L a b e l T e x t ( ’


complementAdresse ’ ) + ”&nbsp ; :</span> ” +
35 a d r e s s e . g e t P r o p e r t y ( ’ complementAdresse ’ ) + ” ,<br />” ;
36 }
37
38 htmlCode += ”<span c l a s s =\” a d r e s s e I t e m \”>” + moduleAdresse . g e t L a b e l T e x t ( ’
c o d e P o s t a l ’ ) + ”&nbsp ; :</span> ” +
39 a d r e s s e . g e t P r o p e r t y ( ’ c o d e P o s t a l ’ ) + ”<br />” +
40 ”<span c l a s s =\” a d r e s s e I t e m \”>” + moduleAdresse . g e t L a b e l T e x t ( ’ v i l l e ’ ) + ”&
nbsp ; :</span> ” +
41 a d r e s s e . g e t P r o p e r t y ( ’ v i l l e ’ ) + ”<br />” +
42 ”<span c l a s s =\” a d r e s s e I t e m \”>” + moduleAdresse . g e t L a b e l T e x t ( ’ pays ’ ) + ”&
nbsp ; :</span> ” +
43 a d r e s s e . g e t P r o p e r t y ( ’ pays ’ ) + ”<br />” ;
44
45 i f ( adresse . hasError () ) {
46 var e r r o r L i s t = a d r e s s e . g e t E r r o r L i s t ( ) ;
47 htmlCode += ”<s trong>C e r t a i n s champs ont une e r r e u r :</s trong><br />” ;
48 f or ( var i =0 ; i<e r r o r L i s t . l e n g t h ; i ++){
49 i f ( i > 0) {
50 htmlCode += ” , ” ;
51 }
52 htmlCode += e r r o r L i s t [ i ] ;
53 }
54 }
55
56 return htmlCode ;
57 }]) ;
58
59 /* *
60 * Mé t h o d e de g éné r a t i o n de code HTML pour une i n s t a n c e d ’ a d r e s s e .
61 * L ’ a d r e s s e e s t a f f i c h é e s u r une l i g n e , s a n s mention d e s e r r e u r s .
62 *
63 * @method g e t H t m l D e v e l o p p e d
64 * @augments myApp . v i e w . a d r e s s e
65 * @param { O b j e c t } a d r e s s e − sp é c i f i c a t i o n d e s p r o p r i é t é s d ’ une i n s t a n c e d ’
adresse
66 * @param { s t r i n g } a d r e s s e . i d − i d e n t i f i a n t u n i q u e de l ’ i n s t a n c e
67 * @param { s t r i n g } a d r e s s e . numeroRue − numero de rue
68 * @param { s t r i n g } a d r e s s e . rue − nom de rue
69 * @param { s t r i n g } a d r e s s e . complementAdresse − compl é ment d ’ a d r e s s e ( l i e u dut , b
â timent , r é s i d e n c e , e t c . )
70 * @param { s t r i n g } a d r e s s e . c o d e P o s t a l − code p o s t a l
71 * @param { s t r i n g } a d r e s s e . v i l l e − nom de v i l l e
72 * @param { s t r i n g } a d r e s s e . pays − nom de pays
73 */
74 myApp . addModule . apply (myApp . view . a d r e s s e , [ ” getHtmlCompact ” , function ( a d r e s s e ) {
75 var htmlCode = ” ” ;
76
77 i f ( a d r e s s e . g e t P r o p e r t y ( ’ numeroRue ’ ) ) {
78 htmlCode += a d r e s s e . g e t P r o p e r t y ( ’ numeroRue ’ ) + ” , ” ;
79 }
80
81 htmlCode += a d r e s s e . g e t P r o p e r t y ( ’ rue ’ ) + ” , ” ;
82 i f ( a d r e s s e . g e t P r o p e r t y ( ’ complementAdresse ’ ) ) {
83 htmlCode += a d r e s s e . g e t P r o p e r t y ( ’ complementAdresse ’ ) + ” , ” ;

38
Chapitre 2 : Programmation Fonctionnelle et Objet en JavaScript

84 }
85 htmlCode += a d r e s s e . g e t P r o p e r t y ( ’ c o d e P o s t a l ’ ) + ” ” +
86 adresse . getProperty ( ’ v i l l e ’ ) + ” , ” +
87 a d r e s s e . g e t P r o p e r t y ( ’ pays ’ ) ;
88 return htmlCode ;
89 }]) ;

exemples/objet/ex07_adresseView.html
1 /<! d o c t y p e HTML>
2 <html lang=” f r ”>
3 <head>
4 <meta charset=”UTF−8” />
5 <t i t l e>A f f i c h a g e d ’ A d r e s s e s</ t i t l e>
6 <l i nk rel=” s t y l e s h e e t ” href=” ex07_adresseView . c s s ” />
7 </head>
8 <body>
9 <!−− Cr é a t i o n de l ’ a p p l i c a t i o n v i d e avec deux mé t h o d e s −−>
10 <s c r i p t src=” e x 0 4 _ s t r u c t u r e A p p l i c a t i o n . j s ”></s c r i p t>
11 <!−− Cr é a t i o n de sous−module r e g e x U t i l de myApp . m e t i e r −−>
12 <s c r i p t src=” . /ex05_modulePatternRegex . j s ”></s c r i p t>
13 <!−− Cr é a t i o n de sous−module a d r e s s e de myApp . m e t i e r −−>
14 <s c r i p t src=” . /ex06_moduleMetierAdresse . j s ”></s c r i p t>
15 <!−− Cr é a t i o n d ’ u n e mé thode f a b r i q u e d ’ a d r e s s e de myApp . m e t i e r . a d r e s s e −−>
16 <s c r i p t src=” . / e x 0 6 _ f a b r i q u e A d r e s s e . j s ”></s c r i p t>
17 <!−− Cr é a t i o n de f o n c t i o n s d ’ a f f i c h a g e dans myApp . m e t i e r . a d r e s s e −−>
18 <s c r i p t src=” . /ex07_adresseView . j s ”></s c r i p t>
19
20 <!−− Ajout d’un main e t ex é c u t i o n −−>
21 <s c r i p t>
22
23 var t e s t A f f i c h e A d r e s s e = function ( a d r e s s e ) {
24 document . w r i t e ( ”<span s t y l e = \ ”width :260 px ; display : i n l i n e − b l o c k ;
vertical−align : top ; \ ”>” +
25 myApp . view . a d r e s s e . getHtmlDevelopped ( a d r e s s e )+ ”<br /><br />” +
26 myApp . view . a d r e s s e . getHtmlCompact ( a d r e s s e ) +
27 ”</span>” ) ;
28
29 };
30
31 // Ajout d ’ u n e mé t h o d e mainFunction
32 myApp . addModule ( ” mainFunction ” , function ( ) {
33 // c r é a t i o n d ’ u n e i n s t a n c e

39
Rémy Malgouyres, http://malgouyres.org Programmation Web Côté Client, JS et jQuery

34 var a d r e s s e = myApp . m e t i e r . a d r e s s e . c r e a t e I n s t a n c e ( {
35 id : ” 04 a b f 8 5 b c 9 ” ,
36 numeroRue : ”2 b i s ” ,
37 r u e : ”Rue de l ’ a Paix ” ,
38 // o u b l i du champs complementAdresse
39 c o d e P o s t a l : ” 630000 ” ,
40 v i l l e : ” Clermont−Ferrand ” ,
41 pays : ” France 2”
42 }) ;
43
44 testAfficheAdresse ( adresse ) ;
45
46 a d r e s s e . s e t P r o p e r t y ( ” complementAdresse ” , ” \ ”Bâ t i m e n t 3D\ ” ” ) ;
47 a d r e s s e . s e t P r o p e r t y ( ” c o d e P o s t a l ” , ” 63000 ” ) ;
48 a d r e s s e . s e t P r o p e r t y ( ” pays ” , ” France ” ) ;
49 a d r e s s e . s e t P r o p e r t y ( ”numeroRue” , ”@#*m” ) ;
50
51 testAfficheAdresse ( adresse ) ;
52 }) ;
53
54 // Exé c u t i o n de l a mé t h o d e mainFunction
55 myApp . mainFunction ( ) ;
56 </s c r i p t>
57 <s c r i p t src=” j q u e r y . j s ”></s c r i p t>
58 </body>
59 </html>

40
Chapitre 3

Constructeurs, Prototype et Patterns


Associés

3.1 Constructeurs
Un classe en Javascript se crée à partir d’un constructeur, qui est une fonction dont le nom est
le nom de la classe à créer. À l’intérieur du constructeur, les propriétés de la classe sont créées
et initialisées à l’aide de l’identificateur this. Le constructeur retourne un unique objet dont
les propriétés correspondent à celles qui ont été initialisées à l’aide de l’identificateur this. En
d’autres termes, le constructeur retourne une instance de la classe. Par convention, les noms
de constructeurs commencent par une majuscule.
exemples/objetPrototype/ex01_classeTelephone.js
1 /* *
2 * C o n s t r u c t e u r de t é l é phone . Notez l a m a j u s c u l e s u r l e nom .
3 * @constructor
4 * @param { s t r i n g } t e l 1 − l e numé ro de t é l é phone .
5 * @param { s t r i n g } [ t e l 2 ] − un second numé ro de t é l é phone .
6 */
7 var Telephone = function ( t e l 1 , /* argument o p t i o n n e l */ t e l 2 ) {
8
9 var checkPhone = function ( t e l ) {
10 // Test d ’ e x p r e s s i o n r é g u l i è r e a p r è s s u p p r e s s i o n d e s e s p a c e s e t t a b u l a t i o n s
11 i f ( typeof t e l . l i b e l l e !== ” s t r i n g ” | | typeof t e l . numero !== ” s t r i n g ” | |
12 /^ ((\+33) | 0 ) [0 −9]{9} $/ . t e s t ( t e l . numero . r e p l a c e ( / \ s /g , ’ ’ ) ) !== true ) {
13 throw {
14 name : ” I l l e g a l A r g u m e n t E x c e p t i o n ” ,
15 message : ”Numé ro de t é l é phone \” ” + t e l . l i b e l l e + ” : ” + t e l . numero + ”
\” i n v a l i d e ”
16 }
17 }
18 };
19
20 checkPhone ( t e l 1 ) ;
21 // Cré a t i o n d ’ un a t t r i b u t de l a c l a s s e
22 t h i s . t e l 1=t e l 1 ;
23
24 i f ( t e l 2 !== u n d e f i n e d ) {
25 checkPhone ( t e l 2 ) ;
26 // Cré a t i o n d ’ un a t t r i b u t de l a c l a s s e

41
Rémy Malgouyres, http://malgouyres.org Programmation Web Côté Client, JS et jQuery

27 t h i s . t e l 2=t e l 2 ;
28 }
29
30 /* *
31 * @method g etH tm l
32 * @return { s t r i n g } l e code HTML pour a f f i c h e r une i n s t a n c e .
33 */
34 t h i s . getHtml = function ( ) {
35 var htmlCode = t h i s . t e l 1 . l i b e l l e + ” : ” + t h i s . t e l 1 . numero + ”<br />” ;
36 i f ( t h i s . t e l 2 !== u n d e f i n e d ) {
37 htmlCode += t h i s . t e l 2 . l i b e l l e + ” : ” + t h i s . t e l 2 . numero + ”<br />” ;
38 }
39 return htmlCode ;
40 };
41 }

exemples/objetPrototype/ex01_classeTelephone.html
1 <! doctype HTML>
2 <html l a n g=” f r ”>
3 <head>
4 <meta c h a r s e t=”UTF−8” />
5 <t i t l e>C l a s s e s</ t i t l e>
6 <s c r i p t s r c=” . / e x 0 1 _ c l a s s e T e l e p h o n e . j s ”></s c r i p t>
7 </head>
8 <body>
9 <s c r i p t>
10 try {
11 // Appel du c o n s t r u c t e u r a v e c l e mot c l é ”new” :
12 var t e l = new Telephone ( { l i b e l l e : ” Maison ” , numero : ”+33 1 23 45 67 89 ” } ,
13 { l i b e l l e : ” M o b i l e ” , numero : ” 09 87 65 43 21 ” } ) ;
14 // U t i l i s a t i o n de l a mé t h o d e ge tH tm l ( )
15 document . w r i t e ( ”<p>” + t e l . getHtml ( ) + ”</p>” ) ;
16 } catch ( e r r ) {
17 a l e r t ( e r r . message ) ;
18 }
19 </s c r i p t>
20 </body>
21 </html>

Un constructeur doit systématiquement être employé avec le mot clé new. En


effet, l’emploi d’un constructeur sans le mot clé new, qui ne génère, en soi, aucune
exception ni warning conduit à un comportement imprévisible, généralement
catastrophique. D’où l’importance de respecter la convention que les noms
de constructeurs commencent par une majuscule, contrairement à toutes
les autres fonctions ou variables.

3.2 Prototypes
3.2.1 Notion de prototype
Les méthodes de classes telles que vues jusqu’à présent ont l’inconvénient que ces méthodes
sont des propriétés des objets, qui existent en autant d’exemplaires qu’il y a d’instance des

42
Chapitre 3 : Constructeurs, Prototype et Patterns Associés

objets, alors qu’elles sont constantes.


Pour éviter cela, on peut mettre les méthodes non pas directement dans l’objet, mais dans
son prototype. Le prototype est lui-même une propriété de l’objet, mais qui est partagée entre
tous les objets de la classe (il s’agit d’une variable de classe). Toutes les variables de classes
doivent être crées au niveau du prototype.
exemples/objetPrototype/ex02_prototype.js
1
2 /* *
3 * Augmente l a c l a s s e Telephone en e j o u t a n t une mé t h o d e au p r o t o t y p e de
Telephone
4 * @method g e t H t m l B y L i b e l l e
5 * @return { s t r i n g } l e code HTML pour a f f i c h e r une i n s t a n c e .
6 */
7 Telephone . p r o t o t y p e . getNumero = function ( l i b e l l e ) {
8 i f ( t h i s . t e l 1 . l i b e l l e . toLowerCase ( ) === l i b e l l e . toLowerCase ( ) ) {
9 return t h i s . t e l 1 . numero ;
10 }
11 i f ( t h i s . t e l 2 !== u n d e f i n e d &&
12 t h i s . t e l 2 . l i b e l l e . toLowerCase ( ) === l i b e l l e . toLowerCase ( ) ) {
13 return t h i s . t e l 2 . numero ;
14 }
15 return ”Numé ro i n e x i s t a n t ” ;
16 };

exemples/objetPrototype/ex02_prototype.html
1 <! doctype HTML>
2 <html l a n g=” f r ”>
3 <head>
4 <meta c h a r s e t=”UTF−8” />
5 <t i t l e>P r o t o t y p e s</ t i t l e>
6 <!−− I n c l u s i o n de l a dé f i n i t i o n de l a c l a s s e Telephone −−>
7 <s c r i p t s r c=” . / e x 0 1 _ c l a s s e T e l e p h o n e . j s ”></s c r i p t>
8 <s c r i p t s r c=” . / e x 0 2 _ p r o t o t y p e . j s ”></s c r i p t>
9 </head>
10 <body>
11 <s c r i p t>
12 try {
13 // Appel du c o n s t r u c t e u r a v e c l e mot c l é ”new” :
14 var t e l = new Telephone ( { l i b e l l e : ” Maison ” , numero : ”+33 1 23 45 67 89 ” } ,
15 { l i b e l l e : ” M o b i l e ” , numero : ” 09 87 65 43 21 ” } ) ;
16 // U t i l i s a t i o n de l a mé t h o d e getNumero ( ) du p r o t o t y p e
17 document . w r i t e ( ”<p>” + t e l . getNumero ( ” maison ” ) + ”</p>” ) ;
18 document . w r i t e ( ”<p>” + t e l . getNumero ( ” m o b i l e ” ) + ”</p>” ) ;
19 document . w r i t e ( ”<p>” + t e l . getNumero ( ” t r a v a i l ” ) + ”</p>” ) ;
20 } catch ( e r r ) {
21 a l e r t ( e r r . message ) ;
22 }
23 </s c r i p t>
24 </body>
25 </html>

La méthode Object.prototype.hasOwnProperty() permet de tester si une propriété d’un


objet existe au niveau de l’objet lui-même, ou au niveau de son prototype, ou encore du

43
Rémy Malgouyres, http://malgouyres.org Programmation Web Côté Client, JS et jQuery

prototype de son prototype.


Le fonctionnement de la notion de prototype est le suivant : Lors d’une tentative d’accès
à un propriété de l’objet, la propriété est tout d’abord recherchée au niveau des propriétés
propres. Seulement si la propriété n’existe pas dans les propriétés propres, elle est ensuite
recherchée dans le prototype de l’objet. Si elle n’existe pas non plus à ce niveau, la propriété
est recherchée dans le prototype du prototype, et ainsi de suite...
Ce processus s’appelle la délégation et il permet de spécialiser les objets, en les faisant hériter
des propriétés d’un prototype, tout en leur permettant de surcharger (redéfinir) les données ou
méthodes. Ceci constitue un mécanisme très souple d’héritage, entièrement dynamique.

3.2.2 Surcharge des méthodes du prototype : l’exemple de toString


La méthode toString, qui permet de convertir un objet en chaîne de caractères (par exemple
pour l’afficher) a une implémentation par défaut définie dans le prototype de la classe Object.
On peut la surcharger dans le prototype de notre classe Telephone pour changer le compor-
tement par défaut de la méthode toString et mettre en forme à notre guise les numéros de
téléphone.
exemples/objetPrototype/ex03_toString.js
1 /* *
2 * @override t o S t r i n g
3 * @return { s t r i n g } une cha î ne de c a r a c t è r e r e p r é s e n t a t n t l ’ i n s t a n c e de
Telephone
4 */
5
6 Telephone . p r o t o t y p e . t o S t r i n g = function ( ) {
7 var t e x t e = t h i s . t e l 1 . l i b e l l e + ” : ” + t h i s . t e l 1 . numero ;
8 i f ( t h i s . t e l 2 !== u n d e f i n e d ) {
9 t e x t e += ” e t ” + t h i s . t e l 2 . l i b e l l e + ” : ” + t h i s . t e l 2 . numero ;
10 }
11 return t e x t e ;
12 }

exemples/objetPrototype/ex03_toString.html
1 <! doctype HTML>
2 <html l a n g=” f r ”>
3 <head>
4 <meta c h a r s e t=”UTF−8” />
5 <t i t l e>S u r c h a r g e d e s p r o p r i é t é s du p r o t o t y p e</ t i t l e>
6 <!−− I n c l u s i o n de l a dé f i n i t i o n de l a c l a s s e Telephone −−>
7 <s c r i p t s r c=” . / e x 0 1 _ c l a s s e T e l e p h o n e . j s ”></s c r i p t>
8 <s c r i p t s r c=” . / e x 0 3 _ t o S t r i n g . j s ”></s c r i p t>
9 </head>
10 <body>
11 <s c r i p t>
12 try {
13 // Appel du c o n s t r u c t e u r a v e c l e mot c l é ”new” :
14 var t e l = new Telephone ( { l i b e l l e : ” Maison ” , numero : ”+33 1 23 45 67 89 ” } ,
15 { l i b e l l e : ” M o b i l e ” , numero : ” 09 87 65 43 21 ” } ) ;
16 // U t i l i s a t i o n i m p l i c i t e de l a mé t h o d e t o S t r i n g ( ) ( c o n v e r s i o n )
17 document . w r i t e ( ”<p>” + t e l + ”</p>” ) ;
18 } catch ( e r r ) {

44
Chapitre 3 : Constructeurs, Prototype et Patterns Associés

19 a l e r t ( e r r . message ) ;
20 }
21 </s c r i p t>
22 </body>
23 </html>

3.3 Exemple : assurer l’implémentation d’interfaces


Voici une classe Interface, qui possède comme attribut un array de noms de méthodes, et qui
permet de vérifier qu’un objet possède bien des méthodes avec les noms correspondants. Notons
que nous ne vérifions pas que lés méthodes correspondent bien à un prototype déterminé, mais
seulement que les noms de méthodes sont présents.

exemples/objetPrototype/ex04_interfaceImplementation.js
1 /* *
2 * Dé f i n i t une ” i n t e r f a c e ” , a v e c un nom e t un e n s e m b l e de mé t h o d e s .
3 * Ceci nous p e r m e t t r a de v é r i f i e r qu ’ un c e r t a i n nombre d ’ op é r a t i o n s
4 * s o n t pr é s e n t e s dans un o b j e t J a v a S c r i p t .
5 *
6 * @constructor I n t e r f a c e
7 * @param { s t r i n g } name − nom de l ’ i n t e r f a c e
8 * @param { s t r i n g [ ] } methods − t a b l e a u c o n t e n a n t l e s noms d e s mé t h o d e s de l ’
interface .
9 */
10 var I n t e r f a c e = function ( methods ) {
11
12 i f ( methods . l e n g t h === u n d e f i n e d ) {
13 throw {
14 name : ” I l l e g a l A r g u m e n t ” ,
15 message : ”Une i n t e r f a c e né c e s s i t e un a r r a y ( ou array−l i k e ) de noms de mé
thodes . ”
16 };
17 }
18
19 // Cré a t i o n d ’ une p r o p r i é t é pour s t o c k e r l e nom de l ’ i n t e r f a c
20 // Cré a t i o n d ’ un t a b l e a u pour s o c k e r l e s noms de mé t h o d e d
21 t h i s . methods = [ ] ;
22 // pour chaque nom de mé t h o d e
23 for ( var i = 0 ; i < methods . l e n g t h ; ++i ) {
24 // Vé r i f i c a t i o n de t y p e
25 i f ( typeof methods [ i ] !== ’ s t r i n g ’ ) {
26 throw {
27 name : ” I l l e g a l A r g u m e n t ” ,
28 message : ” Les noms de mé t h o d e s d ’ une i n t e r f a c e d o i v e n t ê t r e de t y p e
string .”
29 };
30 }
31 // Ajout du nom de mé t h o d e
32 t h i s . methods . push ( methods [ i ] ) ;
33 }
34 };
35
36 /* *

45
Rémy Malgouyres, http://malgouyres.org Programmation Web Côté Client, JS et jQuery

37 * Vé r i f i e qu ’ un o b j e t ” i m p l é mente une i n t e r f a c e ” , en ce s e n s qu ’ i l comporte


38 * un c e r t a i n nombre de mé t h o d e s ( p r o p r i é t é s de t y p e f o n c t i o n ) q u i ont l e s
39 * mêmes noms que l e s mé t h o d e s de l ’ i n t e r f a c e .
40 *
41 * @method isImplementedBy
42 * @param { O b j e c t } o b j e t − o b j e t q u i d o i t i m p l é menter l ’ i n t e r f a c e .
43 * @return { b o o l e a n | s t r i n g } t r u e s i l ’ o b j e t comporte t o u t e s l e s mé t h o d e s de l ’
interface ,
44 * un message d ’ e r r e u r i n d i q u a n t une mé t h o d e q u i n ’ e s t pas pr é s e n t e dans l ’ o b j e t
sinon .
45 */
46 I n t e r f a c e . p r o t o t y p e . isImplementedBy = function ( o b j e t ) {
47 // Pour chaque nom de mé t h o d e
48 for ( var i = 0 ; i < t h i s . methods . l e n g t h ; ++i ) {
49 var methodName = t h i s . methods [ i ] ;
50 // S i l ’ o b j e t n ’ a pas de p r o p r i é t é de ce nom q u i s o i t de t y p e f o n c t i o n
51 i f ( ! o b j e t [ methodName ] | | typeof o b j e t [ methodName ] !== ’ f u n c t i o n ’ ) {
52 return ”L ’ o b j e t n ’ i m p l é mente pas l a mé t h o d e ” + methodName ;
53 }
54 }
55 return true ;
56 };

Voici un exemple dans lequel nous définissions deux interfaces attendues de nos modules
métier :

1. L’interface attendue d’un module permet de tester la présence d’un certain nombre de
méthodes statiques ;

2. L’interface attendue des instances permet de s’assurer de la présence d’un certain nombre
de méthodes sur les instances.

Remarque. Dans nos exemples, une méthode getModule permet d’obtenir le module corres-
pondant à une instance (par exemple myApp.metier.adresse) à partir d’une instance d’adresse
obtenue par la fabrique createInstance de ce même module). Nous verrons dans la partie 3.4
comment simplifier notre interface des modules métier en supprimant le besoin de cette mé-
thode getModule.

exemples/objetPrototype/ex04_interfaceImplementation.html
1 <! doctype HTML>
2 <html l a n g=” f r ”>
3 <head>
4 <meta c h a r s e t=”UTF−8” />
5 <t i t l e>Impl é mentation d ’ i n t e r f a c e s</ t i t l e>
6 <!−− Chargement de l ’ ensemble d e s modules mé t i e r −−>
7 <s c r i p t s r c=” . / m o d u l e s M e t i e r . j s ”></s c r i p t>
8 <!−− C l a s s e de v é r i f i c a t i o n de l ’ impl é mentation d ’ i n t e r f a c e s −−>
9 <s c r i p t s r c=” . / e x 0 4 _ i n t e r f a c e I m p l e m e n t a t i o n . j s ”></s c r i p t>
10 </head>
11 <body>
12 <s c r i p t>
13
14 // Ajout d ’ une mé t h o d e mainFunction

46
Chapitre 3 : Constructeurs, Prototype et Patterns Associés

15 myApp . addModule ( ” mainFunction ” , function ( ) {


16
17 // Dé f i n i t i o n de l ’ i n t e r f a c e commune aux modules mé t i e r ( a d r e s s e , personne
, etc .)
18 var metierCommonMethods = new I n t e r f a c e (
19 [ ” getPropertyList ” , ” getLabelText ” , ” testRegex ” , ” createInstance ” ] ) ;
20 // Dé f i n i t i o n de l ’ i n t e r f a c e commune aux i n s t a n c e s d e s modules mé t i e r (
a d r e s s e , personne , e t c . )
21 var metierCommonInstanceMethods = new I n t e r f a c e (
22 [ ” getModule ” , ” g e t P r o p e r t y ” , ” s e t P r o p e r t y ” , ” h a s E r r o r ” , ” g e t E r r o r M e s s a g e
” , ” getErrorList ” ]) ;
23
24 // c r é a t i o n d ’ une i n s t a n c e
25 var monObjet = myApp . m e t i e r . a d r e s s e . c r e a t e I n s t a n c e ( {
26 i d : ” 04 a b f 8 5 b c 9 ” ,
27 numeroRue : ”2 b i s ” ,
28 r u e : ”Rue de l ’ a Paix ” ,
29 complementAdresse : ”Bâ t i m e n t 3D” ,
30 c o d e P o s t a l : ” 63000 ” ,
31 v i l l e : ” Clermont−Ferrand ” ,
32 pays : ” France ”
33 }) ;
34
35 var t e s t I n s t a n c e I n t e r f a c e = metierCommonInstanceMethods . isImplementedBy (
monObjet ) ;
36 i f ( t e s t I n s t a n c e I n t e r f a c e !== true ) {
37 document . w r i t e ( ”<p>” + t e s t I n s t a n c e I n t e r f a c e + ”</p>” ) ;
38 } else {
39 var module = monObjet . getModule ( ) ;
40 var t e s t M o d u l e I n t e r f a c e = metierCommonMethods . isImplementedBy ( module ) ;
41 i f ( t e s t M o d u l e I n t e r f a c e !== true ) {
42 document . w r i t e ( ”<p>” + t e s t M o d u l e I n t e r f a c e + ”</p>” ) ;
43 } else {
44 document . w r i t e ( ”<p>L ’ o b j e t s e m b l e b i e n i m p l é menter l e s mé t h o d e s
r e q u i s e s .</p>” ) ;
45 }
46 }
47 }) ;
48
49 // Exé c u t i o n de l a mé t h o d e mainFunction
50 myApp . mainFunction ( ) ;
51 </s c r i p t>
52 </body>
53 </html>

3.4 Fabrique d’Objets Métier avec prototype


Le but de cette partie est de redéfinir la babrique d’instances d’adresses (méthode
myApp.metier.adresse.createInstance
de la partie 2.6) pour que les méthodes du module (méthodes getPropertyList, getLabelText,
testRegex, createInstance) soient accessibles au niveau des instances (comme méthode dans
le prototype des instances). Les avantages de cette implémentation sont les suivants :
• Interface plus simple dans laquelle la méthode getModule() des instances, qui retournait

47
Rémy Malgouyres, http://malgouyres.org Programmation Web Côté Client, JS et jQuery

l’objet myApp.metier.adresse a été supprimée, puisque l’objet myApp.metier.adresse


constituera désormais le prototype des instances crées par notre fabrique. Les méthodes
du module seront ainsi accessibles de manière transparentes via l’instance.

• Le code source des méthodes d’instance (getProperty, setProperty, hasError, getErrorMessage,


getErrorList) n’est compilé qu’une seule fois, car il se trouve comme variable locale pri-
vée d’un module, est est ensuite exposé via de simples alias dans l’interface des instances.

Nous avons aussi ajouté la possibilité, en passant un argument inputObj égal à null, de
réer une instance par défaut (id aléatoire et autres attributs vides) Ceci permet par exemple
d’initialiser un formulaire vide pour créer une nouvelle instance.
exemples/objetPrototype/ex05_fabriqueAdressePrototype.js
1 /* *
2 * Fabrique qui cr é e des o b j e t s repr é sentant des adresse , suiva nt l e ” pattern
module ” .
3 * Le paramètre s p e c de n o t r e f o n c t i o n e s t un o b j e t c o n t e n a n t l e s p r o p r i é t é s d ’
une a d r e s s e à c r é e r .
4 *
5 * @method c r e a t e I n s t a n c e
6 * @augments myApp . m e t i e r . a d r e s s e
7 * @param { O b j e c t | n u l l } i n p u t O b j − sp é c i f i c a t i o n d e s p r o p r i é t é s d ’ une i n s t a n c e d
’ a d r e s s e . S i i n p u t O b j e s t n u l l , on c r é e une a d r e s s e par d é f a u t ( i d a l é
atoire , autres propri é t és vide ) .
8 * @param { s t r i n g } i n p u t O b j . i d − i d e n t i f i a n t u n i q u e de l ’ i n s t a n c e
9 * @param { s t r i n g } i n p u t O b j . numeroRue − numero de rue
10 * @param { s t r i n g } i n p u t O b j . rue − nom de rue
11 * @param { s t r i n g } i n p u t O b j . complementAdresse − compl é ment d ’ a d r e s s e ( l i e u dut ,
b â timent , r é s i d e n c e , e t c . )
12 * @param { s t r i n g } i n p u t O b j . c o d e P o s t a l − code p o s t a l
13 * @param { s t r i n g } i n p u t O b j . v i l l e − nom de v i l l e
14 * @param { s t r i n g } i n p u t O b j . pays − nom de pays
15 */
16 myApp . addModule . apply (myApp . m e t i e r . a d r e s s e , [ ” c r e a t e I n s t a n c e ” , function ( ) {
17
18 // //////////////////////////////////////////////
19 // I n t e r f a c e p u b l i q u e du module
20
21 /* *
22 * Cré a t i o n d ’ un c o n s t r u c t e u r p r i v é , c r é ant une c l a s s e dont une i n s t a n c e
23 * p r i v é e c o n t i e n d r a l e s donn é e s de l ’ i n s t a n c e , rendue p u b l i q u e v i a l ’
interface
24 * du module .
25 *
26 * L ’ u t i l i s a t i o n d ’ un c o n s t r u c t e u r e s t de d é f i n i r l e s mé t h o d e p r i v é e s au
n i v e a u du p r o t o t y p e .
27 */
28 var P r i v a t e I n s t a n c e C o n s t r u c t o r = function ( ) {
29
30 /* *
31 * O b j e t p r i v é c o n t e n a n t l e s p r o p r i é t é s ( id , rue , . . . ) de l ’ i n s t a n c e ,
initialement vide
32 * @member
33 * @private
34 */

48
Chapitre 3 : Constructeurs, Prototype et Patterns Associés

35 this . adresse = {} ;
36 /* *
37 * O b j e t p r i v é c o n t e n a n t l e s messages d ’ e r r e u r a s s o c i é s aux p r o p r i é t é s
attendues des i n s t a n c e s .
38 * @member
39 * @private
40 */
41 this . dataError = false ;
42
43 };
44
45 /* *
46 * A j o u t e une p r o p r i é t é ( message d ’ e r r e u r ) dans d a t a E r r o r
47 * @method addError
48 * @private
49 */
50 P r i v a t e I n s t a n c e C o n s t r u c t o r . p r o t o t y p e . addError = function ( propertyName , message
){
51 // s i d a t a E r r o r n ’ e x i s t e pas , on l e c r é e
52 i f ( t h i s . d a t a E r r o r === f a l s e ) {
53 this . dataError = {} ;
54 }
55 // Ajout d ’ une p r o p r i é t é
56 t h i s . d a t a E r r o r [ propertyName ] = message ;
57 };
58
59 /* *
60 * S e t t e r : i n i t i a l i s e l a v a l e u r pour une p r o p r i é t é a t t e n d u e s d ’ une i n s t a n c e .
61 * En c a s d ’ e r r e u r un message pour c e t t e p r o p r i é t é e s t e s t a j o u t é dans
dataError .
62 * En l ’ a b s e n c e d ’ e r r e u r , une é v e n t u e l l e e r r e u r pr é c é d e n t e e s t e f f a c é e .
63 * @method addError
64 * @private
65 */
66 P r i v a t e I n s t a n c e C o n s t r u c t o r . p r o t o t y p e . s e t P r o p e r t y O r E r r o r = function (
propertyName , v a l u e ) {
67 var r e s u l t T e s t R e g e x = myApp . m e t i e r . a d r e s s e . t e s t R e g e x ( propertyName , v a l u e ) ;
68 // On i n t i a l i s e l a p r o p r i é t é de l ’ a d r e s s e
69 t h i s . a d r e s s e [ propertyName ] = v a l u e ;
70 // S i l a v a l i d a t i o n par e x p r e s s i o n r é g u l i è r e e s t p a s s é e
71 i f ( r e s u l t T e s t R e g e x === true ) {
72 // On e f f a c e une v i e i l l e e r r e u r é v e n t u e l l e
73 delete t h i s . d a t a E r r o r [ propertyName ] ;
74 } else {
75 // On i n i t a l i s e l a p r o p r i é t é de l ’ o b j e t d e s e r r e u r s .
76 // a v e c l e message d ’ e r r e u r .
77 P r i v a t e I n s t a n c e C o n s t r u c t o r . p r o t o t y p e . addError . c a l l ( this , propertyName , ”
Propri é t é ” + value +
78 ” i n v a l i d e : ” + resultTestRegex ) ;
79 }
80 };
81
82
83 /* *
84 * @return { b o o l e a n } t r u e s ’ i l y a ( au moins ) une e r r e u r , f a l s e s i n o n
85 */

49
Rémy Malgouyres, http://malgouyres.org Programmation Web Côté Client, JS et jQuery

86 P r i v a t e I n s t a n c e C o n s t r u c t o r . p r o t o t y p e . h a s E r r o r = function ( ) {
87 i f ( t h i s . d a t a E r r o r === f a l s e ) {
88 return f a l s e ;
89 }
90 f or ( var propertyName in t h i s . d a t a E r r o r ) {
91 i f ( t h i s . d a t a E r r o r . hasOwnProperty ( propertyName ) ) {
92 return true ;
93 }
94 }
95 return f a l s e ;
96 };
97
98
99 /* *
100 * Ré c u p è r e l a l i s t e d e s champs q u i ont une e r r e u r
101 * @return { s t r i n g [ ] } t a b l e a u d e s noms de p r o r p i é t é s q u i comportent une
erreur .
102 */
103 P r i v a t e I n s t a n c e C o n s t r u c t o r . p r o t o t y p e . g e t E r r o r L i s t = function ( ) {
104 var e r r o r L i s t = [ ] ;
105 for ( var propertyName in t h i s . d a t a E r r o r ) {
106 i f ( t h i s . d a t a E r r o r . hasOwnProperty ( propertyName ) ) {
107 e r r o r L i s t . push ( propertyName ) ;
108 }
109 }
110 return e r r o r L i s t ;
111 };
112
113 // Géné r a t i o n d ’ un ID a l é a t o i r e en c a s de c r é a t i o n d ’ une n o u v e l l e a d r e s s e
114 // ( c a s où l e s s p e c i f i c a t i o n s i n p u t O b j s o n t n u l l )
115 var generateRandomId = function ( ) {
116 var idLength = 1 0 ;
117 var r e s u l t a t = ” ” ;
118 var h e x a D i g i t s = Array ( ”0” , ”1” , ”2” , ”3” , ”4” , ”5” , ”6 ” , ”7 ” , ”8 ” , ”9 ” , ” a” , ” b ” , ” c ”
, ” d” , ” e ” , ” f ” ) ;
119 var i ;
120 for ( i =0 ; i<10 ; ++i ) {
121 r e s u l t a t += h e x a D i g i t s [ Math . f l o o r ( Math . random ( ) * 1 6 ) ] ;
122 }
123 return r e s u l t a t ;
124 }
125
126 /* *
127 * F a b r i c a t i o n d ’ une i n s t a n c e à p a r t i r d ’ une i n p u t O b j de sp é c i f i c a t i o n s
128 * ( v o i r documentation du module ) e t d ’ une i n s t a n c e p r i v é e v i d e .
129 */
130 var f a b r i q u e I n s t a n c e = function ( inputObj , p r i v a t e I n s t a n c e ) {
131
132 /* *
133 * C o n s t r u c t e u r de l ’ i n s t a n c e q u i s e r a e f f e c t i v e m e n t r e t o u r n é e ( i n s t a n c e
publique ) ,
134 * q u i c r é e l e s donn é e s dans l ’ o b j e t p r i v a t e I n s t a n c e .
135 * Ce c o n s t r u c t e u r c o n t i e n d r a a u s s i l e s mé t h o d e s d ’ i n s t a n c e p u b l i q u e s ,
136 * e t l e s mé t h o d e s ( s t a t i q u e s ) du module dans son p r o t o t y p e .
137 */
138 var P u b l i c I n s t a n c e C o n s t r u c t o r = function ( ) {

50
Chapitre 3 : Constructeurs, Prototype et Patterns Associés

139
140 var a d r e s s e M e t h o d s = myApp . m e t i e r . a d r e s s e ; // r a c o u r c i
141
142 // S i l ’ o b j e t en argument e s t n u l l , on c o n s t r u i t une i n s t a n c e par d é f a u t
( vide )
143 i f ( inputObj === null ) {
144 privateInstance . adresse = {
145 i d : generateRandomId ( ) ,
146 numeroRue : ” ” ,
147 rue : ”” ,
148 complementAdresse : ” ” ,
149 codePostal : ”” ,
150 v i l l e : ”” ,
151 pays : ” ”
152 };
153 } else {
154 // Parcours d e s p r o p r i é t é s de g e t P r o p e r t y L i s t ( )
155 // q u i c o r r e s p o n d e n t aux p r o p r i é t é s de l ’ a d r e s s e à c r é e r
156 for ( var i = 0 ; i < a d r e s s e M e t h o d s . g e t P r o p e r t y L i s t ( ) . l e n g t h ; ++i ) {
157 var propertyName = a d r e s s e M e t h o d s . g e t P r o p e r t y L i s t ( ) [ i ] ;
158 p r i v a t e I n s t a n c e . s e t P r o p e r t y O r E r r o r ( propertyName , inputObj [
propertyName ] ) ;
159 }
160 }
161
162 /* *
163 * A c c e s s e u r pour t o u s l e s membres p r i v é s d ’ i n s t a n c e .
164 * @param { s t r i n g } propertyName − nom de l a p r o p r i é t é a t t e n d u e d ’ une
instance
165 * @return { s t r i n g } l a v a l e u r de l a p r o p r i é t é ou u n d e f i n e d en c a s de nom
de p r o p r i é t é inconnu .
166 */
167 t h i s . g e t P r o p e r t y = function ( propertyName ) {
168 return p r i v a t e I n s t a n c e . a d r e s s e [ propertyName ] ;
169 };
170
171 /* *
172 * S e t t e r : i n i t i a l i s e l a v a l e u r pour une p r o p r i é t é a t t e n d u e s d ’ une
i n s t a n c e a p r è s un t e s t .
173 * En c a s d ’ e r r e u r , un message pour c e t t e p r o p r i é t é e s t e s t a j o u t é dans
dataError .
174 * En l ’ a b s e n c e d ’ e r r e u r , une é v e n t u e l l e e r r e u r pr é c é d e n t e e s t e f f a c é e .
175 * @param { s t r i n g } propertyName − nom de l a p r o p r i é t é a t t e n d u e d ’ une
instance
176 * @param { s t r i n g } v a l u e − v a l e u r à p r e n d r e pour l a p r o p r i é t é a t t e n d u d ’
une i n s t a n c e
177 * @return { b o o l e a n } t r u e s ’ i l y a au moins une e r r e u r , f a l s e s i n o n
178 */
179 t h i s . s e t P r o p e r t y = function ( propertyName , v a l u e ) {
180 return p r i v a t e I n s t a n c e . s e t P r o p e r t y O r E r r o r ( propertyName , v a l u e ) ;
181 };
182
183 /* *
184 * @return { b o o l e a n } t r u e s ’ i l y a ( au moins ) une e r r e u r , f a l s e s i n o n
185 */
186 t h i s . h a s E r r o r = function ( ) {

51
Rémy Malgouyres, http://malgouyres.org Programmation Web Côté Client, JS et jQuery

187 return p r i v a t e I n s t a n c e . h a s E r r o r ( ) ;
188 };
189
190 /* *
191 * Donne l ’ a c c è s aux d i f f é r e n t s messages d ’ e r r e u r .
192 * @param { s t r i n g } propertyName − nom de p r o p r i é t é d ’ une i n s t a n c e d ’
adresse
193 * @return { s t r i n g | u n d e f i n e d } l e message d ’ e r r e u r pour une p r o p r i é t é s ’
i l e x i s t e ou u n d e f i n e d en l ’ a b s e n c e d ’ e r r e u r
194 */
195 t h i s . g e t E r r o r M e s s a g e = function ( propertyName ) {
196 return p r i v a t e I n s t a n c e . d a t a E r r o r [ propertyName ] ;
197 };
198
199 /* *
200 * Ré c u p è r e l a l i s t e d e s champs q u i ont une e r r e u r
201 * @return { s t r i n g [ ] } t a b l e a u d e s noms de p r o r p i é t é s q u i comportent une
erreur .
202 */
203 t h i s . g e t E r r o r L i s t = function ( ) {
204 return p r i v a t e I n s t a n c e . g e t E r r o r L i s t ( ) ;
205 };
206 } ; // f i n du P u b l i c I n s t a n c e C o n s t r u c t o r
207
208 // MISE À DISPOSITION DES MÉTHODES DU MODULE VIA LE PROTOTYPE
209 P u b l i c I n s t a n c e C o n s t r u c t o r . p r o t o t y p e = myApp . m e t i e r . a d r e s s e ;
210
211 return new P u b l i c I n s t a n c e C o n s t r u c t o r ( inputObj ) ;
212
213 } ; // f i n de l a f o n c t i o n f a b r i q u e I n s t a n c e
214
215 // C o n s t r u c t i o n d ’ une i n s t a n c e a v e c
216 return function ( inputObj ) {
217 // Un o b j e t P r i v a t e I n s t a n c e C o n s t r u c t o r e s t c o n s t r u i t pour l ’ o c c a s i o n
218 return f a b r i q u e I n s t a n c e ( inputObj , new P r i v a t e I n s t a n c e C o n s t r u c t o r ( ) ) ;
219 };
220 } ( ) // f i n de l a mé t h o d e c r e a t e I n s t a n c e
221 ] ) ; // f i n de l ’ a p p e l ” a p p l y ” de l a mé t h o d e myApp . addModule

exemples/objetPrototype/ex05_fabriqueAdressePrototype.html
1 <! doctype HTML>
2 <html l a n g=” f r ”>
3 <head>
4 <meta c h a r s e t=”UTF−8” />
5 <t i t l e>Cr é a t i o n d ’ I n s t a n c e s d ’ A d r e s s e s</ t i t l e>
6 <l i nk r e l=” s t y l e s h e e t ” , h r e f=” b a s i c S t y l e . c s s ” />
7 </head>
8 <body>
9 <!−− Cr é a t i o n de l ’ a p p l i c a t i o n v i d e avec deux mé t h o d e s −−>
10 <s c r i p t s r c=” . . / o b j e t / e x 0 4 _ s t r u c t u r e A p p l i c a t i o n . j s ”></s c r i p t>
11 <!−− Cr é a t i o n de sous−module r e g e x U t i l de myApp . m e t i e r −−>
12 <s c r i p t s r c=” . . / o b j e t / ex05_modulePatternRegex . j s ”></s c r i p t>
13 <!−− Cr é a t i o n de sous−module a d r e s s e de myApp . m e t i e r −−>
14 <s c r i p t s r c=” . . / o b j e t / ex06_moduleMetierAdresse . j s ”></s c r i p t>
15 <!−− Cr é a t i o n d ’ une mé thode f a b r i q u e d ’ a d r e s s e de myApp . m e t i e r . a d r e s s e −−>

52
Chapitre 3 : Constructeurs, Prototype et Patterns Associés

16 <s c r i p t s r c=” . / e x 0 5 _ f a b r i q u e A d r e s s e P r o t o t y p e . j s ”></s c r i p t>


17
18 <!−− Ajout d ’ un main e t ex é c u t i o n −−>
19 <s c r i p t>
20
21 var t e s t A f f i c h e A d r e s s e = function ( a d r e s s e ) {
22 document . w r i t e ( ”<div>” ) ;
23 document . w r i t e ( ”<span><h2>Donné e s :</h2>” +
24 ”<s trong>” + a d r e s s e . g e t L a b e l T e x t ( ’ id ’ ) +
25 ” :</s trong>” + a d r e s s e . g e t P r o p e r t y ( ’ id ’ ) + ”<br />” +
26 ”<s trong>” + a d r e s s e . g e t L a b e l T e x t ( ’ numeroRue ’ ) +
27 ” :</s trong> ” + a d r e s s e . g e t P r o p e r t y ( ’ numeroRue ’ ) + ”<br />” +
28 ”<s trong>” + a d r e s s e . g e t L a b e l T e x t ( ’ rue ’ ) +
29 ” :</s trong> ” + a d r e s s e . g e t P r o p e r t y ( ’ rue ’ ) + ”<br />” +
30 ”<s trong>” + a d r e s s e . g e t L a b e l T e x t ( ’ complementAdresse ’ ) +
31 ” :</s trong> ” + a d r e s s e . g e t P r o p e r t y ( ’ complementAdresse ’ ) + ”<br />” +
32 ”<s trong>” + a d r e s s e . g e t L a b e l T e x t ( ’ c o d e P o s t a l ’ ) +
33 ” :</s trong> ” + a d r e s s e . g e t P r o p e r t y ( ’ c o d e P o s t a l ’ ) + ”<br />” +
34 ”<s trong>” + a d r e s s e . g e t L a b e l T e x t ( ’ v i l l e ’ ) +
35 ” :</s trong> ” + a d r e s s e . g e t P r o p e r t y ( ’ v i l l e ’ ) + ”<br />” +
36 ”<s trong>” + a d r e s s e . g e t L a b e l T e x t ( ’ pays ’ ) +
37 ” :</s trong> ” + a d r e s s e . g e t P r o p e r t y ( ’ pays ’ ) +
38 ”</span>” ) ;
39
40 // v a r i a n t e en énumé r a n t automatiquement l e s p r o p r i é t é s
41 var htmlCode = ”<span><h2>E r r e u r s :</h2>” ;
42 for ( var i =0 ; i < a d r e s s e . g e t P r o p e r t y L i s t ( ) . l e n g t h ; ++i ) {
43 var propertyName = a d r e s s e . g e t P r o p e r t y L i s t ( ) [ i ] ;
44 htmlCode += ”<s trong>” + a d r e s s e . g e t L a b e l T e x t ( propertyName ) + ” :</s
trong> ” +
45 a d r e s s e . g e t E r r o r M e s s a g e ( propertyName ) + ”<br />” ;
46 }
47
48 htmlCode += ”</span>” ;
49 document . w r i t e ( htmlCode ) ;
50 document . w r i t e ( ”</div>” ) ;
51 };
52
53 // Ajout d ’ une mé t h o d e mainFunction
54 myApp . addModule ( ” mainFunction ” , function ( ) {
55 // c r é a t i o n d ’ une i n s t a n c e
56 var a d r e s s e = myApp . m e t i e r . a d r e s s e . c r e a t e I n s t a n c e ( {
57 i d : ” 04 a b f 8 5 b c 9 ” ,
58 numeroRue : ”2 b i s ” ,
59 r u e : ”Rue de l ’ a Paix ” ,
60 // o u b l i du champs complementAdresse
61 c o d e P o s t a l : ” 630000 ” ,
62 v i l l e : ” Clermont−Ferrand ” ,
63 pays : ” France 2 ”
64 }) ;
65
66 testAfficheAdresse ( adresse ) ;
67
68 a d r e s s e . s e t P r o p e r t y ( ” complementAdresse ” , ” \”Bâ t i m e n t 3D\” ” ) ;
69 a d r e s s e . s e t P r o p e r t y ( ” c o d e P o s t a l ” , ” 63000 ” ) ;
70 a d r e s s e . s e t P r o p e r t y ( ” pays ” , ” France ” ) ;

53
Rémy Malgouyres, http://malgouyres.org Programmation Web Côté Client, JS et jQuery

71 a d r e s s e . s e t P r o p e r t y ( ”numeroRue” , ”@#*m” ) ;
72
73 testAfficheAdresse ( adresse ) ;
74 }) ;
75
76 // Exé c u t i o n de l a mé t h o d e mainFunction
77 myApp . mainFunction ( ) ;
78 </s c r i p t>
79 </body>
80 </html>

En utilisant cette fabrique, le code la méthode myApp.view.adresse.getHtmlDevelopped


est un peu différent car il faut supprimer les appels à la méthode getModule, en accédant
directement au module via le prototype des instances.
En outre, l’interface des objets métiers se trouve simplifiée, car il n’y a plus qu’une seule
interface, au lieu de deux dans l’exemple de la partie 3.3.
exemples/objetPrototype/ex07_interfaceImplementationPrototype.html
1 <! doctype HTML>
2 <html l a n g=” f r ”>
3 <head>
4 <meta c h a r s e t=”UTF−8” />
5 <t i t l e>Impl é mentation d ’ i n t e r f a c e s</ t i t l e>
6 <!−− Cr é a t i o n de l ’ a p p l i c a t i o n v i d e avec deux mé t h o d e s −−>
7 <s c r i p t s r c=” . . / o b j e t / e x 0 4 _ s t r u c t u r e A p p l i c a t i o n . j s ”></s c r i p t>
8 <!−− Cr é a t i o n de sous−module r e g e x U t i l de myApp . m e t i e r −−>
9 <s c r i p t s r c=” . . / o b j e t / ex05_modulePatternRegex . j s ”></s c r i p t>
10 <!−− Cr é a t i o n de sous−module a d r e s s e de myApp . m e t i e r −−>
11 <s c r i p t s r c=” . . / o b j e t / ex06_moduleMetierAdresse . j s ”></s c r i p t>
12 <!−− Cr é a t i o n d ’ une mé thode f a b r i q u e d ’ a d r e s s e de myApp . m e t i e r . a d r e s s e −−>
13 <s c r i p t s r c=” . / e x 0 5 _ f a b r i q u e A d r e s s e P r o t o t y p e . j s ”></s c r i p t>
14 <!−− C l a s s e de v é r i f i c a t i o n de l ’ impl é mentation d ’ i n t e r f a c e s −−>
15 <s c r i p t s r c=” . / e x 0 4 _ i n t e r f a c e I m p l e m e n t a t i o n . j s ”></s c r i p t>
16 </head>
17 <body>
18 <s c r i p t>
19
20 // Ajout d ’ une mé t h o d e mainFunction
21 myApp . addModule ( ” mainFunction ” , function ( ) {
22
23 // Dé f i n i t i o n de l ’ i n t e r f a c e commune aux i n s t a n c e s d e s modules mé t i e r (
a d r e s s e , personne , e t c . )
24 var metierCommonInstanceMethods = new I n t e r f a c e (
25 [ ” getPropertyList ” , ” getLabelText ” , ” testRegex ” , ” getProperty ” , ”
se tPr op er ty ” , ” hasError ” , ” getErrorMessage ” , ” g e t E r r o r L i s t ” ] ) ;
26
27 // c r é a t i o n d ’ une i n s t a n c e
28 var monObjet = myApp . m e t i e r . a d r e s s e . c r e a t e I n s t a n c e ( {
29 i d : ” 04 a b f 8 5 b c 9 ” ,
30 numeroRue : ”2 b i s ” ,
31 r u e : ”Rue de l ’ a Paix ” ,
32 complementAdresse : ”Bâ t i m e n t 3D” ,
33 c o d e P o s t a l : ” 63000 ” ,
34 v i l l e : ” Clermont−Ferrand ” ,
35 pays : ” France ”
36 }) ;

54
Chapitre 3 : Constructeurs, Prototype et Patterns Associés

37
38 var t e s t I n s t a n c e I n t e r f a c e = metierCommonInstanceMethods . isImplementedBy (
monObjet ) ;
39 if ( testInstanceInterface !== true ) {
40 document . w r i t e ( ”<p>” + t e s t I n s t a n c e I n t e r f a c e + ”</p>” ) ;
41 } else {
42 document . w r i t e ( ”<p>L ’ o b j e t s e m b l e b i e n i m p l é menter l e s mé t h o d e s
r e q u i s e s .</p>” ) ;
43 }
44 }) ;
45
46 // Exé c u t i o n de l a mé t h o d e mainFunction
47 myApp . mainFunction ( ) ;
48 </s c r i p t>
49 </body>
50 </html>

3.5 Patterns pseudo-classique (à éviter)


Dans l’exemple suivant, nous créons une classe Personne qui hérite des propriétés de la classe
Adresse. Pour celà :

1. le constructeur d’Adresse est appelé explicitement dans le constructeur de Personne ;

2. la classe Adresse est déclarée comme superclass de la classe Personne ;

3. Les méthodes qui existent au niveau du prototype de la classe Adresse et qui doivent
être spécifiées pour des personnes sont surchargées au niveau du prototype de la classe
Personne.

Dans l’exemple suivant, nous surchargeons l’accesseur de la propriété ville et la méthode


toString.
exemples/vieux/objet.vieux/ex14_extension_de_classe.js
1 function A d r e s s e ( numeroRue , rue , complement , c o d e P o s t a l , v i l l e ) {
2 i f ( numeroRue . match ( /^ ( [ 0 − 9 ] * ) (([0 −9]+) (\ ?) ( ( ( b i s ) | ( t e r ) ) ) ?) $/ ) ) {
3 t h i s . numeroRue = numeroRue . r e p l a c e ( / \ s+/g , ’ ’ ) ;
4 } else {
5 throw new E r r o r ( ”Numé ro de l a rue i n v a l i d e . ” ) ;
6 }
7
8 i f ( r u e . match ( /^ ( ( ( [ a−zA−Zê é è öàöÉÈÊÀÖË\ \− \.\ ,0 −9\ ] ) | ( \ ” ) ) | ( \ ’ ) ) {1 ,300} $/ ) )
{
9 t h i s . r u e = r u e . r e p l a c e ( / \ s+/g , ’ ’ ) ;
10 ;
11 } else {
12 throw new E r r o r ( ”Nom de l a rue / p l a c e i n v a l i d e . ” ) ;
13 }
14
15 i f ( complement . match ( /^ ( ( ( [ a−zA−Zê é è öàöÉÈÊÀÖË\ \− \.\ ,0 −9\ ] ) | ( \ ” ) ) | ( \ ’ ) )
{0 ,300} $/ ) ) {
16 t h i s . complement = complement . r e p l a c e ( / \ s+/g , ’ ’ ) ;
17 } else {

55
Rémy Malgouyres, http://malgouyres.org Programmation Web Côté Client, JS et jQuery

18 throw new E r r o r ( ” Complement d ’ a d r e s s e i n v a l i d e . ” ) ;


19 }
20
21 i f ( c o d e P o s t a l . match ( /^ [0 −9]{5} $/ ) ) {
22 this . codePostal = codePostal ;
23 } else {
24 throw new E r r o r ( ”Code p o s t a l i n v a l i d e . ” ) ;
25 }
26
27 i f ( v i l l e . match ( /^ ( ( ( [ a−zA−Zê é è öàöÉÈÊÀÖË\ \− \.\ ,0 −9\ ] ) | ( \ ” ) ) | ( \ ’ ) ) {0 ,300} $/ )
) {
28 t h i s . v i l l e = v i l l e . r e p l a c e ( / \ s+/g , ’ ’ ) ;
29 } else {
30 throw new E r r o r ( ”Nom de v i l l e i n v a l i d e . ” ) ;
31 }
32 }
33
34 A d r e s s e . p r o t o t y p e . g e t V i l l e = function ( ) {
35 return t h i s . v i l l e ;
36 }
37
38 A d r e s s e . p r o t o t y p e . t o S t r i n g = function ( ) {
39 var r e s u l t a t = t h i s . numeroRue ;
40 i f ( t h i s . numeroRue != ” ” )
41 r e s u l t a t += ” , ” ;
42 r e s u l t a t += t h i s . r u e + ” , ” ;
43 r e s u l t a t += t h i s . complement ;
44 i f ( t h i s . complement != ” ” )
45 r e s u l t a t += ” , ” ;
46 r e s u l t a t += t h i s . v i l l e + ”<br />” ;
47 return r e s u l t a t ;
48 }
49
50 function Personne (nom , prenom , numeroRue , rue , complement , c o d e P o s t a l , v i l l e ) {
51 A d r e s s e . c a l l ( this , numeroRue , rue , complement , c o d e P o s t a l , v i l l e ) ;
52 t h i s . nom = nom ;
53 t h i s . prenom = prenom ;
54 }
55
56 Personne . s u p e r c l a s s = A d r e s s e ;
57 Personne . p r o t o t y p e . g e t V i l l e = function ( ) {
58 return A d r e s s e . p r o t o t y p e . g e t V i l l e . c a l l ( t h i s ) ;
59 }
60
61 Personne . p r o t o t y p e . t o S t r i n g = function ( ) {
62 return t h i s . nom+” , ”+t h i s . prenom+” , ”+A d r e s s e . p r o t o t y p e . t o S t r i n g . c a l l ( t h i s ) ;
63 }

exemples/vieux/objet.vieux/ex14_extention_de_classe.html
1 <! doctype HTML>
2 <html l a n g=” f r ”>
3 <head>
4 <meta c h a r s e t=”UTF−8” />
5 <t i t l e>Chainage de c o n s t r u c t e u r s</ t i t l e>
6 <s c r i p t s r c=” . / e x 1 4 _ e x t e n s i o n _ d e _ c l a s s e . j s ”></s c r i p t>

56
Chapitre 3 : Constructeurs, Prototype et Patterns Associés

7 </head>
8 <body>
9 <p>
10 <s c r i p t>
11
12 try {
13 var p e r s = new Personne ( ” Dujardin ” , ” Jean ” , ” 10 t e r ” , ” rue de l ’ a v e n i r ” , ’ ”Le
Rastou ” ’ , ” 86098 ” , ” Les F l o t s B l e u s ” ) ;
14 document . w r i t e ( p e r s ) ;
15 document . w r i t e ( ”<br />L ’ a d r e s s e s e t r o u v e dans l a v i l l e de \” ”+p e r s . g e t V i l l e ( )+
” \”. ”) ;
16 } catch ( e r r ) {
17 alert ( err ) ;
18 }
19 </s c r i p t>
20 <p>
21 </body>
22 </html>

57
Chapitre 4

Interfaces Hommes Machines (IHM )

4.1 Filtrage Basique des Inputs d’un Formulaire


L’exemple suivant montre comment filtrer les attributs d’un formulaires côté client en affichant
immédiatement un message d’erreur lors de la saisie d’une valeur incorrecte. On associe à chaque
événement onchange de chaque attribut une fonction JavaScript qui réalisera le filtrage.
exemples/gui/ex01_basicForm.js
1 // a l i a s v e r s l e module d ’ e x p r e s s i o n s r é g u l i è r e s
2 var r e g e x U t i l = myApp . m e t i e r . r e g e x U t i l ;
3 /* *
4 * G e s t i o n n a i r e d ’ é v é nement onchange de l ’ i n p u t d ’ ID ” mainForm_titre ” .
5 * C e t t e mé t h o d e e f f e c t u e l e f i l t r a g e par e x e p r e s s i o n r é g u l i è r e .
6 * @method f i l t e r T i t r e
7 */
8 var f i l t e r T i t r e = function ( ) {
9 var t i t r e V a l u e = $ ( ”#mainForm_titre ” ) . v a l ( ) ;
10 // E x p r e s s i o n s du l a n g a g e c o u r a n t e t c h i f f r e s
11 var r e s u l t R e g e x T e s t = r e g e x U t i l . t e s t R e g e x L a t i n 1 W i t h D i g i t s ( {
12 chaine : titreValue ,
13 minLength : 1
14 }) ;
15 // M o d i f i c a t i o n du contenu du span d ’ ID ” error_mainForm_titre ”
16 i f ( r e s u l t R e g e x T e s t === true ) {
17 $ ( ”#error_mainForm_titre ” ) . empty ( ) ;
18 } else {
19 $ ( ”#error_mainForm_titre ” ) . html (
20 ” Erreur : l e t i t r e ne d o i t c o n t e n i r que l e s l e t t r e s e t c h i f f r e s<br />” ) ;
21 }
22 };
23
24 /* *
25 * G e s t i o n n a i r e d ’ é v é nement onchange de l ’ i n p u t d ’ ID ”mainForm_resume ” .
26 * C e t t e mé t h o d e e f f e c t u e l e f i l t r a g e par e x e p r e s s i o n r é g u l i è r e .
27 * @function f i l t e r Titre
28 */
29 var f i l t e r Resume = function ( ) {
30 var t i t r e V a l u e = $ ( ”#mainForm_resume” ) . v a l ( ) ;
31 // E x p r e s s i o n s du l a n g a g e c o u r a n t e t c h i f f r e s e t p o n c t u a t i o n
32 var r e s u l t R e g e x T e s t = r e g e x U t i l . t e s t R e g e x L a t i n 1 W i t h D i g i t s P u n c t u a t i o n ( {
33 chaine : titreValue ,

58
Chapitre 4 : Interfaces Hommes Machines (IHM )

34 minLength : 1
35 }) ;
36 // M o d i f i c a t i o n du contenu du span d ’ ID ” error_mainForm_resume ”
37 i f ( r e s u l t R e g e x T e s t === true ) {
38 $ ( ”#error_mainForm_resume ” ) . empty ( ) ;
39 } else {
40 $ ( ”#error_mainForm_resume ” ) . html (
41 ” Erreur : l e r ésumé ne d o i t c o n t e n i r que l e s l e t t r e s e t c h i f f r e s ” +
42 ” ou d e s c a r a c t è r e s de p o n c t u a t i o n<br />” ) ;
43 }
44 };

exemples/gui//ex01_basicForm.html
1 /<! d o c t y p e HTML>
2 <html lang=” f r ”>
3 <head>
4 <meta charset=”UTF−8” />
5 <t i t l e>F i l t r a g e d ’ i n p u t s</ t i t l e>
6 <l i nk rel=” s t y l e s h e e t ” href=” b a s i c S t y l e . c s s ” />
7 </head>
8 <body>
9 <h1>S a i s i e d’un f i l m</h1>
10 <form id=”mainForm” action=” p o s t ”>
11
12 <!−− i n p u t avec g e s t i o n n a i r e de l ’ é v é nement onchange −−>
13 <span id=” error_mainForm_titre ” class= ” errorMsg ”></span>
14 <l a b e l for=” mainForm_titre ”>T i t r e :</ l a b e l>
15 <i nput type=” t e x t ” id=” mainForm_titre ” s i z e=” 15 ”
16 placeholder=” T i t r e du f i l m ” onchange= ” f i l t e r T i t r e ( ) ” /><br />
17
18 <!−− t e x t a r e a avec g e s t i o n n a i r e de l ’ é v é nement onchange −−>

59
Rémy Malgouyres, http://malgouyres.org Programmation Web Côté Client, JS et jQuery

19 <span id=” error_mainForm_resume ” class= ” errorMsg ”></span>


20 <l a b e l for=”mainForm_resume”>Résumé :</ l a b e l>
21 <textarea id=”mainForm_resume” rows=” 10 ” cols=” 50 ”
22 placeholder=” S a i s i s s e z v o t r e r ésumé ” onchange= ” f i l t e r Resume ( ) ”></textarea>
23
24 </form>
25 <!−− I n c l u s i o n de l a s t r u c t u r e d ’ a p p l i c a t i o n e t du module r e g e x U t i l −−>
26 <s c r i p t src=” m o d u l e s M e t i e r . j s ”></s c r i p t>
27 <!−− I n c l u s i o n de jQuery pour l e s é v é nements e t m a n i p u l a t i o n du DOM −−>
28 <s c r i p t src=” j q u e r y . j s ”></s c r i p t>
29 <s c r i p t src=” e x 0 2 _ m e d i a t o r I n p u t F i l t e r . j s ”></s c r i p t>
30 <s c r i p t src=” ex01_basicForm . j s ”></s c r i p t>
31 </body>
32 </html>

4.2 Pattern Mediator pour le filtrage d’attributs


L’inconvénient du filtrage présenté dans la partie 4.1 est que, dans le code HTML d’un champs
du formulaire lui-même, on doit déclarer une méthode de filtrage spécifique pour ce champs
(attribut onchange de l’élément HTML input ou textarea).
Dans l’architecture d’application que nous proposons par la suite, la méthode de filtrage
ne sera pas codée en dûr dans le module chargé de générer le formulaire, mais plutôt dans
les tests d’expressions régulières effectués dans les modules métier. En particulier, la méthode
précise dépendra de l’instance et de la propriété considérée, ce qui entraînerai un fort couplage
(interdépendance) des méthodes chargées de l’IHM et des classes métier (ou du modèle).
Nous savons par expérience que ce type de couplage va provoquer des difficultés pour la
maintenance et l’évolution de notre application (comme par exemple la migration de nos objet
métier côté serveur avec NodeJS). Nous allons maintenant introduire un pattern qui a pour
vocation de découpler le déclenchement des événements (via, en l’occurence, des événements
utilisateurs onchange) de l’implémentation des opérations correspondantes sur les données
métier, ou les données du modèle. Ce pattern est une généralisation du pattern Observer.
Dans notre exemple, un module Mediator va enregistrer les méthodes callbacks (qui ne
sont que des fonctions JavaScript) associées à des événements. L’exécution des ces claabacks
(en l’occurence la réaction à un événement onchange) sera déclenchée par la publication de
l’événement en question par l’intermédiaire du Mediator.
exemples/gui/ex02_mediatorInputFilter.js
1
2 /* *
3 * Ajout d ’ un module c t r l ( c o n t r ô l e u r s ) à l ’ a p p l i c a t i o n .
4 * @module c t r l
5 * @augments myApp
6 */
7 myApp . addModule . apply (myApp, [ ” c t r l ” , { } ] ) ;
8
9 /* *
10 * Impl é m e n ta ti o n du p a t t e r n ”Mé d i a t o r ” pour g é r e r l e f i l t r a g e d e s i n p u t s de
formulaires .
11 * @module m e d i a t o r I n p u t F i l t e r
12 * @augments myApp . c t r l
13 */

60
Chapitre 4 : Interfaces Hommes Machines (IHM )

14 myApp . addModule . apply (myApp . c t r l , [ ” m e d i a t o r I n p u t F i l t e r ” , function ( ) {


15
16 // //////////////////////////////////////////////
17 // P r o p r i é t é s e t mé t h o d e s ” s t a t i q u e s ” p r i v é e s
18
19 /* *
20 * C o l l e c t i o n , i n d e x é e par ID de f o r m u l a i r e de c a l l b a c k s d ’ é v é nements l i é s à
d i f f é r e n s f o r m u l a i r e s ( t y p i q u e m e n t : é v é nement onchange d ’ un i n p u t ) .
21 * @private
22 */
23 var m _ s u b s c r i p t i o n L i s t s ;
24
25 /* *
26 * I n i t i a l i s e ( ou r é i n i t i a l i s e ) l ’ e n s e m b l e d e s l i s t e s d ’ é v é nements à l a
col le cti on vide .
27 * @private
28 */
29 var i n i t = function ( ) {
30 m _ s u b s c r i p t i o n L i s t s ={} ;
31 };
32
33 // I n n i t i a l i s e r une f o i s l ’ e n s e m b l e d e s l i s t e s d ’ é v é nements à l a c o l l e c t i o n
vide .
34 init () ;
35
36 // //////////////////////////////////////////////
37 // I n t e r f a c e p u b l i q u e du module
38
39 /* *
40 * Cré a t i o n d ’ un o b j e t c o n t e n a n t l e s donn é e s e t mé t h o d e s p u b l i q u e s
41 * ( l e s p r o p r i é t é s p u b l i q u e s s o n t r e t o u r n é e s par l a f o n c t i o n ” module ”) .
42 */
43 var p u b l i c I n t e r f a c e M e d i a t o r = {
44
45 /* *
46 * A j o u t e un f o r m u l a i r e e t l a l i s t e ( i n i t i a l e m e n t v i d e ) de s e s c a l l b a c k s
associ és .
47 * S i l e f o r m u l a i r e e s t d é j à g é r é , l a l i s t e de s e s c a l l b a c k s a s s o c i é s e s t
supprim é e e t r é i n i t i a l i s é e à l a l i s t e v i d e .
48 * @param { s t r i n g } formId − l ’ I d du f o r m u l a i r e ( en t a n t qu ’ é l é ment HTML)
49 */
50 addForm : function ( formId ) {
51 m _ s u b s c r i p t i o n L i s t s [ formId ] = {}
52 },
53
54 /* *
55 * Supprime un f o r m u l a i r e e t s e s c a l l b a c k s a s s o c i é s
56 * @param { s t r i n g } formId − l ’ I d du f o r m u l a i r e ( en t a n t qu ’ é l é ment HTML)
57 */
58 removeForm : function ( formId ) {
59 i f ( ! m _ s u b s c r i p t i o n L i s t s . hasOwnProperty ( formId ) ) {
60 return f a l s e ;
61 }
62 delete m _ s u b s c r i p t i o n L i s t s [ formId ] ;
63 return true ;
64 },

61
Rémy Malgouyres, http://malgouyres.org Programmation Web Côté Client, JS et jQuery

65
66 /* *
67 * Ajout d ’ un é v é nement a s s o c i é à un a t t r i b u t de f o r m u l a i r e e t de sa
fonction callback .
68 * S i l ’ é v é nement e x i s t a i t d é j à pour c e t i n p u t , i l e s t é c r a s é .
69 * @param { s t r i n g } formId − l ’ I d du f o r m u l a i r e ( en t a n t qu ’ é l é ment HTML)
70 * @param { s t r i n g } inputName − l e nom de l ’ i n p u t ( ou de l a p r o p r i é t é de l ’
o b j e t mé t i e r a s s o c i é ) .
71 * @param { f u n c t i o n } c a l l b a c k F u n c t i o n − l a f o n c t i o n ( c a l l b a c k ) à a p p e l e r en
c a s de p u b l i c a t i o n de l ’ é v é nement .
72 */
73 s u b s c r i b e : function ( formId , inputName , c a l l b a c k F u n c t i o n ) {
74 i f ( m _ s u b s c r i p t i o n L i s t s . hasOwnProperty ( formId ) ) {
75 m _ s u b s c r i p t i o n L i s t s [ formId ] [ inputName ] = { c a l l b a c k : c a l l b a c k F u n c t i o n } ;
76 } else {
77 throw {name : ” I l l e g a l A r g u m e n t E x c e p t i o n ” ,
78 message : ” Cat é g o r i e d ’ é v é nements ” + eventCateg + ” inconnue du mé
diateur ”
79 };
80 }
81 },
82
83 /* *
84 * P u b l i c a t i o n d ’ un é v é nement a s s o c i é à un a t t r i b u t de f o r m u l a i r e p r o v o q u a n t
l ’ ex é c u t i o n de l a f o n c t i o n c a l l b a c k a s s o c i é e
85 * @param { s t r i n g } formId − l ’ I d du f o r m u l a i r e ( en t a n t qu ’ é l é ment HTML)
86 * @param { s t r i n g } inputName − l e nom de l ’ i n p u t ( ou de l a p r o p r i é t é de l ’
o b j e t mé t i e r a s s o c i é ) .
87 */
88 p u b l i s h : function ( formId , inputName ) {
89
90 i f ( m _ s u b s c r i p t i o n L i s t s . hasOwnProperty ( formId ) ) {
91 i f ( m _ s u b s c r i p t i o n L i s t s [ formId ] . hasOwnProperty ( inputName ) ) {
92 // On a p p e l l e l e c a l l b a k a v e c son
93 m _ s u b s c r i p t i o n L i s t s [ formId ] [ inputName ] . c a l l b a c k ( ) ;
94 }
95 } else {
96 throw {name : ” I l l e g a l A r g u m e n t E x c e p t i o n ” ,
97 message : ” Fo r m u l a i r e d ’ ID ” + formId + ” inconnu du mé d i a t e u r ”
98 };
99 }
100 },
101
102 /* *
103 * Ré i n i t i a l i s e l a c o l l e c t i o n d e s f o r m u l a i r e s g é r é s à une c o l l e c t i o n v i d e .
104 */
105 empty : function ( ) {
106 init () ;
107 }
108 };
109
110 return p u b l i c I n t e r f a c e M e d i a t o r ;
111
112 }() ] ) ;

exemples/gui/ex02_mediatorInputFilter.html

62
Chapitre 4 : Interfaces Hommes Machines (IHM )

1 <! doctype HTML>


2 <html l a n g=” f r ”>
3 <head>
4 <meta c h a r s e t=”UTF−8” />
5 <t i t l e>F i l t r a g e d ’ i n p u t s</ t i t l e>
6 <l i nk r e l=” s t y l e s h e e t ” h r e f=” b a s i c S t y l e . c s s ” />
7 </head>
8 <body>
9 <h1>S a i s i e d ’ un f i l m</h1>
10 <form i d=”mainForm” a c t i o n=” p o s t ”>
11
12 <!−− i n p u t avec g e s t i o n n a i r e de l ’ é v é nement onchange −−>
13 <span i d=” error_mainForm_titre ” c l a s s=” errorMsg ”></span>
14 <l a b e l f or=” mainForm_titre ”>T i t r e :</ l a b e l>
15 <i nput type=” t e x t ” i d=” mainForm_titre ” s i z e=” 15 ”
16 p l a c e h o l d e r=” T i t r e du f i l m ” onchange=” f i l t e r Data ( ’ mainForm ’ , ’ t i t r e ’ ) ” /><b
r />
17
18 <!−− t e x t a r e a avec g e s t i o n n a i r e de l ’ é v é nement onchange −−>
19 <span i d=” error_mainForm_resume ” c l a s s=” errorMsg ”></span>
20 <l a b e l f or=”mainForm_resume”>Résumé :</ l a b e l>
21 <textarea i d=”mainForm_resume” rows=” 10 ” c o l s=” 50 ”
22 p l a c e h o l d e r=” S a i s i s s e z v o t r e r ésumé ” onchange=” f i l t e r Data ( ’ mainForm ’ , ’
resume ’ ) ”></textarea>
23
24 </form>
25 <!−− I n c l u s i o n de l a s t r u c t u r e d ’ a p p l i c a t i o n e t du module r e g e x U t i l −−>
26 <s c r i p t s r c=” m o d u l e s M e t i e r . j s ”></s c r i p t>
27 <!−− I n c l u s i o n de jQuery pour l e s é v é nements e t m a n i p u l a t i o n du DOM −−>
28 <s c r i p t s r c=” j q u e r y . j s ”></s c r i p t>
29 <s c r i p t s r c=” e x 0 2 _ m e d i a t o r I n p u t F i l t e r . j s ”></s c r i p t>
30 <s c r i p t s r c=” ex01_basicForm . j s ”></s c r i p t>
31 <s c r i p t>
32 // Ajout du f o r m u l a i r e ”mainForm” au mé d i a t e u r q u i g è r e r a s e s é v é nements .
33 myApp . c t r l . m e d i a t o r I n p u t F i l t e r . addForm ( ’ mainForm ’ ) ;
34 // E n r e g i s t r e m e n t du c a l l b a c k a s s c o c i é à l ’ é v é nement onchange du t i t r e
35 myApp . c t r l . m e d i a t o r I n p u t F i l t e r . s u b s c r i b e ( ’ mainForm ’ , ’ t i t r e ’ , f i l t e r T i t r e ) ;
36 // E n r e g i s t r e m e n t du c a l l b a c k a s s c o c i é à l ’ é v é nement onchange du r ésumé
37 myApp . c t r l . m e d i a t o r I n p u t F i l t e r . s u b s c r i b e ( ’ mainForm ’ , ’ resume ’ , f i l t e r Resume )
;
38
39 /* *
40 * P u b l i e l ’ é v é nement onchange d ’ un i n p u t a u p r è s du mé d i a t e u r , p r o v o q u a n t l ’
ex é c u t i o n du c a l l b a c k e n r e g i s t r é pour c e t é v é nement .
41 * @ f u n c t i o n f i l t e r Data
42 */
43 var f i l t e r Data = function ( formId , inputName ) {
44 myApp . c t r l . m e d i a t o r I n p u t F i l t e r . p u b l i s h ( formId , inputName ) ;
45 };
46 </s c r i p t>
47 </body>
48 </html>

63
Rémy Malgouyres, http://malgouyres.org Programmation Web Côté Client, JS et jQuery

4.3 Exemple : génération automatique de formulaire d’adresse


4.3.1 Avec l’interface d’objets métier sans prototype
Dans l’exemple suivant, des méthodes d’un module myApp.gui permettent de générer automa-
tiquement les inputs d’un formulaire permettant de saisir les propriétés (ici supposées de type
texte) d’un objte qui implémente des interface qui apparaissent dans l’exemple de la partie 3.3.
Nous appliquons cette méthode pour afficher et filtrer automatiquement un formulaire de
saisie d’une adresse.

exemples/gui/ex03_formsGui.js
1 // Ajout d ’ un module ” g u i ” à n o t r e a p p l i c a t i o n myApp
2 myApp . addModule . apply (myApp, [ ” g u i ” , { } ] ) ;
3
4 /* *
5 * Fo nc ti o n de g éné r a t i o n de l ’ ID d ’ un é l é ment HTML de t y p e i n p u t pr é f i x é par l ’
ID du f o r m u l a i r e
6 * @method myApp . g u i . g e t I n p u t I d
7 * @param { O b j e c t } i n p u t S p e c c o n t i e n t l e s sp é c i f i c a t i o n s de l ’ i n p u t
8 * @param { s t r i n g } i n p u t S p e c . formId i d du f o r m u l a i r e dans l e q u e l l ’ i n p u t s e r a
ins éré
9 * @param { s t r i n g } i n p u t S p e c . propertyName nom de l a p r o p r i é t é de i n p u t S p e c .
o b j e t M e t i e r à s a i s i r dans l ’ i n p u t
10 */
11 myApp . addModule . apply (myApp . gui , [ ” g e t I n p u t I d ” , function ( i n p u t S p e c ) {
12 return i n p u t S p e c . formId + ”_” + i n p u t S p e c . propertyName ;
13 } ] ) ;
14
15 /* *
16 * P u b l i e a u p r è s du Mediator un é v é nement onchange d ’ un I n p u t
17 * @param { s t r i n g } formId i d du f o r m u l a i r e dans l e q u e l l ’ i n p u t s e r a i n s é r é
18 * @param { s t r i n g } propertyName nom de l a p r o p r i é t é de i n p u t S p e c . o b j e t M e t i e r à
s a i s i r dans l ’ i n p u t
19 */
20 myApp . addModule . apply (myApp . gui , [ ” p u b l i s h I n p u t C h a n g e ” , function ( formId ,
propertyName ) {
21 myApp . c t r l . m e d i a t o r I n p u t F i l t e r . p u b l i s h ( formId , propertyName ) ;
22 } ] ) ;
23
24 /* *
25 * Géné r a t i o n du code HTML d ’ un i n p u t .
26 * @method myApp . g u i . g e t T e x t I n p u t C o d e
27 * @param { O b j e c t } i n p u t S p e c c o n t i e n t l e s sp é c i f i c a t i o n s de l ’ i n p u t
28 * @param { O b j e c t } i n p u t S p e c . o b j e t M e t i e r i n t a n c e d ’ un module mé t i e r ( par exemple
i n s t a n c e d ’ a d r e s s e , de p e r so n ne . . . ) .
29 * c e t o b j e t d o i t i m p l é menter d e s i n t e r f a c e s pr é c i s e s (
g e t P r o p e r t y ( ) , getModule ( ) , e t c . )
30 * @param { s t r i n g } i n p u t S p e c . formId i d du f o r m u l a i r e dans l e q u e l l ’ i n p u t s e r a
ins éré
31 * @param { s t r i n g } i n p u t S p e c . propertyName nom de l a p r o p r i é t é de i n p u t S p e c .
o b j e t M e t i e r à s a i s i r dans l ’ i n p u t
32 * @param { s t r i n g } [ i n p u t S p e c . t y p e=t e x t ] t y p e de l ’ i n p u t
33 * @param {number} [ i n p u t S p e c . i n p u t S i z e =10] t a i l l e de l ’ i n p u t ( nombre de
caractères )
34 */

64
Chapitre 4 : Interfaces Hommes Machines (IHM )

35 myApp . addModule . apply (myApp . gui , [ ” g e t I n p u t C o d e ” , function ( i n p u t S p e c ) {


36 // C a l c u l de l ’ ID de l ’ i n p u t :
37 var i n p u t I d = myApp . g u i . g e t I n p u t I d ( i n p u t S p e c ) ;
38
39 // Valeur de l a p r o p r i é t é de l ’ o b j e t pour l ’ a t t r i b u t v a l u e de l ’ i n p u t
40 var p r o p e r t y V a l u e = i n p u t S p e c . o b j e t M e t i e r . g e t P r o p e r t y ( i n p u t S p e c . propertyName
) | | ”” ;
41 // Cré a t i o n d ’ un é v e n t u e l message s i l ’ o b j e t c o m p o r t a i t d é j à une e r r e u r
42 var e r r o r M e s s a g e = i n p u t S p e c . o b j e t M e t i e r . g e t E r r o r M e s s a g e ( i n p u t S p e c .
propertyName ) !== u n d e f i n e d
43 ? i n p u t S p e c . o b j e t M e t i e r . g e t E r r o r M e s s a g e ( i n p u t S p e c . propertyName )
+ ”<br />” : ” ” ;
44
45 var moduleMetier = i n p u t S p e c . o b j e t M e t i e r . getModule ( ) ; // r a c c o u r c i
46
47 // ////////////////////////////////////////////////////////////////////
48 // C a l l b a c k de g e s t i o n du f i l t r a g e de l ’ i n p u t :
49 myApp . c t r l . m e d i a t o r I n p u t F i l t e r . s u b s c r i b e ( i n p u t S p e c . formId , i n p u t S p e c .
propertyName , function ( ) {
50
51 // S i aucun t e s t d ’ e x p r e s s i o n r é g u l i è r e n ’ e s t pr é vu
52 i f ( moduleMetier === u n d e f i n e d | |
53 moduleMetier . t e s t R e g e x === u n d e f i n e d ) {
54 return true ; // a c c e p t e r l a v a l e u r
55 }
56
57 var r e s u l t a t T e s t R e g e x = moduleMetier . t e s t R e g e x ( i n p u t S p e c . propertyName ,
58 document . getElementById ( i n p u t I d ) . v a l u e ) ;
59 i f ( r e s u l t a t T e s t R e g e x !== true ) {
60 document . getElementById ( ” error_ ”+i n p u t I d ) . innerHTML =
r e s u l t a t T e s t R e g e x +”<br />” ;
61 } else {
62 document . getElementById ( ” error_ ”+i n p u t I d ) . innerHTML = ” ” ;
63 }
64 } ) ; // f i n du c a l l b a c k //////////////////////////////////////////////
65
66 var inputType = i n p u t S p e c . inputType === u n d e f i n e d ? ” t e x t ” : i n p u t S p e c .
inputType ;
67 var i n p u t S i z e = i n p u t S p e c . i n p u t S i z e === u n d e f i n e d ? ” 15 ” : i n p u t S p e c .
inputSize ;
68 var l a b e l T e x t = moduleMetier . g e t L a b e l T e x t ( i n p u t S p e c . propertyName ) ;
69 // r e t o u r du code HTML de l ’ i n p u t
70 return ”<span c l a s s =\”errorMsg \” i d =\”error_ ”+i n p u t I d+” \”>” + e r r o r M e s s a g e +
”</span>” +
71 ”<l a b e l f o r =\”” + i n p u t S p e c . propertyName + ” \”>” + l a b e l T e x t + ”</ l a b e l>
” +
72 ”<i nput t y p e =\”” + inputType + ” \” name=\”” + i n p u t S p e c .
propertyName +
73 ” \” i d =\”” + i n p u t I d + ” \” ” + ” v a l u e =\”” + p r o p e r t y V a l u e + ” \” ” +
74 ” s i z e =\”” + i n p u t S i z e + ” \” ” +
75 ” onchange=\”myApp . g u i . p u b l i s h I n p u t C h a n g e ( ’ ” + i n p u t S p e c . formId + ” ’ ,
’ ” + i n p u t S p e c . propertyName + ” ’ ) \” ” + ”/>” ;
76 } ] ) ;
77
78 /* *
79 * Géné r a t i o n du code HTML de l ’ e n s e m b l e d e s i n p u t s d ’ un f o r m u l a i r e .

65
Rémy Malgouyres, http://malgouyres.org Programmation Web Côté Client, JS et jQuery

80 * @method myApp . g u i . getHtmlFormInputs


81 * @param { O b j e c t } o b j e t M e t i e r i n t a n c e d ’ un module mé t i e r ( par exemple i n s t a n c e
d ’ a d r e s s e , de pe r so nn e . . . ) .
82 * c e t o b j e t d o i t i m p l é menter d e s i n t e r f a c e s pr é c i s e s (
g e t P r o p e r t y ( ) , getModule ( ) , e t c . )
83 * @param { s t r i n g } formId i d du f o r m u l a i r e dans l e q u e l l ’ i n p u t s e r a i n s é r é
84 * @retuern { s t r i n g } l e code HTML d e s t o u s l e s i n p u t s c o r r e s p o n d a n t aux p r o p r i é t
é s de l ’ o b j e t mé t i e r .
85 */
86 myApp . addModule . apply (myApp . gui , [ ” getHtmlFormInputs ” , function ( o b j e t M e t i e r ,
formId ) {
87
88 // Dé f i n i t i o n de l ’ i n t e r f a c e commune aux modules mé t i e r ( a d r e s s e , personne ,
etc .)
89 var metierCommonMethods = new I n t e r f a c e (
90 [ ” getPropertyList ” , ” getLabelText ” , ” testRegex ” , ” createInstance ” ] ) ;
91 // Dé f i n i t i o n de l ’ i n t e r f a c e commune aux i n s t a n c e s d e s modules mé t i e r ( a d r e s s e
, personne , e t c . )
92 var metierCommonInstanceMethods = new I n t e r f a c e (
93 [ ” getModule ” , ” g e t P r o p e r t y ” , ” s e t P r o p e r t y ” , ” h a s E r r o r ” , ” g e t E r r o r M e s s a g e ” , ”
getErrorList ” ]) ;
94
95 var t e s t I n t e r f a c e = metierCommonInstanceMethods . isImplementedBy ( o b j e t M e t i e r ) ;
96 var message ;
97 i f ( t e s t I n t e r f a c e !== true ) {
98 message = t e s t I n t e r f a c e ;
99 } else {
100 message = metierCommonMethods . isImplementedBy ( o b j e t M e t i e r . getModule ( ) ) ;
101 i f ( message !== true ) {
102 throw new E r r o r ( message ) ;
103 }
104 }
105
106 // Ajour du f o r m u l a i r e ”mainForm” au mé d i a t e u r q u i g è r e r a s e s é v é nements .
107 myApp . c t r l . m e d i a t o r I n p u t F i l t e r . addForm ( formId ) ;
108
109 var htmlCode = ” ” ;
110
111 var p r o p e r t y L i s t = o b j e t M e t i e r . getModule ( ) . g e t P r o p e r t y L i s t ( ) ;
112
113 // Tous l e s i n p u t s s o n t de t y p e t e x t e , donc on p e u t
114 // f a i r e une b o u c l e a u t o m a t i q u e s u r l e s p r o p r i é t é s .
115 for ( var i =0 ; i < p r o p e r t y L i s t . l e n g t h ; i ++){
116 var propertyName = p r o p e r t y L i s t [ i ] ;
117 // l ’ u t i l i s a t e u r ne p e u t pas m o d i f i e r l ’ ID :
118 i f ( propertyName != ” i d ” ) {
119 // Concat é n a t i o n du code HTML de l ’ i n p u t
120 htmlCode += myApp . g u i . getInputCode (
121 { objetMetier : objetMetier ,
122 propertyName : p r o p e r t y L i s t [ i ] ,
123 formId : formId } ) + ”<br />” ;
124 }
125 }
126
127 return htmlCode ;
128 }]) ;

66
Chapitre 4 : Interfaces Hommes Machines (IHM )

exemples/gui//ex03_formsGui.html
1 /<! d o c t y p e HTML>
2 <html lang=” f r ”>
3 <head>
4 <meta charset=”UTF−8” />
5 <t i t l e>F i l t r a g e d ’ i n p u t s</ t i t l e>
6 <l i nk rel=” s t y l e s h e e t ” href=” b a s i c S t y l e . c s s ” />
7 </head>
8 <body>
9 <h1>S a i s i e d ’ u n e a d r e s s e</h1>
10 <!−− I n c l u s i o n de l a s t r u c t u r e d ’ a p p l i c a t i o n e t du module r e g e x U t i l −−>
11 <s c r i p t src=” m o d u l e s M e t i e r . j s ”></s c r i p t>
12 <!−− I n c l u s i o n de jQuery pour l e s é v é nements e t m a n i p u l a t i o n du DOM −−>
13 <s c r i p t src=” j q u e r y . j s ”></s c r i p t>
14 <s c r i p t src=” e x 0 2 _ m e d i a t o r I n p u t F i l t e r . j s ”></s c r i p t>
15 <s c r i p t src=” ex03_formsGui . j s ”></s c r i p t>
16 <s c r i p t src=” . / e x 1 1 _ i n t e r f a c e I m p l e m e n t a t i o n . j s ”></s c r i p t>
17 <s c r i p t>
18
19 // Ajout d ’ u n e mé t h o d e mainFunction
20 myApp . addModule ( ” mainFunction ” , function ( ) {
21
22 // c r é a t i o n d ’ u n e i n s t a n c e
23 var a d r e s s e = myApp . m e t i e r . a d r e s s e . c r e a t e I n s t a n c e ( {
24 id : ” 04 a b f 8 5 b c 9 ” ,
25 numeroRue : ”2 bis@ ” ,
26 r u e : ”Rue de l ’ a Paix ” ,
27 complementAdresse : ”Bâ t i m e n t 3D” ,
28 c o d e P o s t a l : ” 63000 ” ,
29 v i l l e : ” Clermont−Ferrand ” ,
30 pays : ” France ”
31 }) ;
32
33 // Géné r a t i o n du f o r m u l a i r e a v e c l e s c a l l b a c k s
34 document . w r i t e ( ”<form id= \ ”mainForm\ ” method=\ ” p o s t \ ”>” +
35 myApp . g u i . getHtmlFormInputs ( a d r e s s e , ”mainForm” ) +
36 ”<l a b e l></ l a b e l><i nput type= \ ” submit \ ” value= \ ” v a l i d e r \ ”/>” +

67
Rémy Malgouyres, http://malgouyres.org Programmation Web Côté Client, JS et jQuery

37 ”</form>” ) ;
38 }) ;
39
40 // Exé c u t i o n de l a mé t h o d e mainFunction
41 myApp . mainFunction ( ) ;
42 </s c r i p t>
43 </body>
44 </html>

4.3.2 Avec l’interface d’objets métier utilisant le prototype


En utilisant le fabrique d’instances d’objets métier de la partie 3.4, le code de génération du
formulaire est un peu plus simple (une seule interface à tester et suppression des appels de la
méthode getModule :

exemples/gui/ex04_formsGuiPrototype.js
1 // Ajout d ’ un module ” g u i ” à n o t r e a p p l i c a t i o n myApp
2 myApp . addModule . apply (myApp, [ ” g u i ” , { } ] ) ;
3
4 /* *
5 * Fo nc ti o n de g éné r a t i o n de l ’ ID d ’ un é l é ment HTML de t y p e i n p u t pr é f i x é par l ’
ID du f o r m u l a i r e
6 * @method myApp . g u i . g e t I n p u t I d
7 * @param { O b j e c t } i n p u t S p e c c o n t i e n t l e s sp é c i f i c a t i o n s de l ’ i n p u t
8 * @param { s t r i n g } i n p u t S p e c . formId i d du f o r m u l a i r e dans l e q u e l l ’ i n p u t s e r a
ins éré
9 * @param { s t r i n g } i n p u t S p e c . propertyName nom de l a p r o p r i é t é de i n p u t S p e c .
o b j e t M e t i e r à s a i s i r dans l ’ i n p u t
10 */
11 myApp . addModule . apply (myApp . gui , [ ” g e t I n p u t I d ” , function ( i n p u t S p e c ) {
12 return i n p u t S p e c . formId + ”_” + i n p u t S p e c . propertyName ;
13 } ] ) ;
14
15 /* *
16 * P u b l i e a u p r è s du Mediator un é v é nement onchange d ’ un I n p u t
17 * @param { s t r i n g } formId i d du f o r m u l a i r e dans l e q u e l l ’ i n p u t s e r a i n s é r é
18 * @param { s t r i n g } propertyName nom de l a p r o p r i é t é de i n p u t S p e c . o b j e t M e t i e r à
s a i s i r dans l ’ i n p u t
19 */
20 myApp . addModule . apply (myApp . gui , [ ” p u b l i s h I n p u t C h a n g e ” , function ( formId ,
propertyName ) {
21 myApp . c t r l . m e d i a t o r I n p u t F i l t e r . p u b l i s h ( formId , propertyName ) ;
22 } ] ) ;
23
24 /* *
25 * Géné r a t i o n du code HTML d ’ un i n p u t .
26 * @method myApp . g u i . g e t T e x t I n p u t C o d e
27 * @param { O b j e c t } i n p u t S p e c c o n t i e n t l e s sp é c i f i c a t i o n s de l ’ i n p u t
28 * @param { O b j e c t } i n p u t S p e c . o b j e t M e t i e r i n t a n c e d ’ un module mé t i e r ( par exemple
i n s t a n c e d ’ a d r e s s e , de p e r so n ne . . . ) .
29 * c e t o b j e t d o i t i m p l é menter d e s i n t e r f a c e s pr é c i s e s (
g e t P r o p e r t y ( ) , getModule ( ) , e t c . )
30 * @param { s t r i n g } i n p u t S p e c . formId i d du f o r m u l a i r e dans l e q u e l l ’ i n p u t s e r a
ins éré

68
Chapitre 4 : Interfaces Hommes Machines (IHM )

31 * @param { s t r i n g } i n p u t S p e c . propertyName nom de l a p r o p r i é t é de i n p u t S p e c .


o b j e t M e t i e r à s a i s i r dans l ’ i n p u t
32 * @param { s t r i n g } [ i n p u t S p e c . t y p e=t e x t ] t y p e de l ’ i n p u t
33 * @param {number} [ i n p u t S p e c . i n p u t S i z e =10] t a i l l e de l ’ i n p u t ( nombre de
caractères )
34 */
35 myApp . addModule . apply (myApp . gui , [ ” g e t I n p u t C o d e ” , function ( i n p u t S p e c ) {
36 // C a l c u l de l ’ ID de l ’ i n p u t :
37 var i n p u t I d = myApp . g u i . g e t I n p u t I d ( i n p u t S p e c ) ;
38
39 // Valeur de l a p r o p r i é t é de l ’ o b j e t pour l ’ a t t r i b u t v a l u e de l ’ i n p u t
40 var p r o p e r t y V a l u e = i n p u t S p e c . o b j e t M e t i e r . g e t P r o p e r t y ( i n p u t S p e c . propertyName
) | | ”” ;
41 // Cré a t i o n d ’ un é v e n t u e l message s i l ’ o b j e t c o m p o r t a i t d é j à une e r r e u r
42 var e r r o r M e s s a g e = i n p u t S p e c . o b j e t M e t i e r . g e t E r r o r M e s s a g e ( i n p u t S p e c .
propertyName ) !== u n d e f i n e d
43 ? i n p u t S p e c . o b j e t M e t i e r . g e t E r r o r M e s s a g e ( i n p u t S p e c . propertyName )
+ ”<br />” : ” ” ;
44
45 // ////////////////////////////////////////////////////////////////////
46 // C a l l b a c k de g e s t i o n du f i l t r a g e de l ’ i n p u t :
47 myApp . c t r l . m e d i a t o r I n p u t F i l t e r . s u b s c r i b e ( i n p u t S p e c . formId , i n p u t S p e c .
propertyName , function ( ) {
48
49 var r e s u l t a t T e s t R e g e x = i n p u t S p e c . o b j e t M e t i e r . t e s t R e g e x ( i n p u t S p e c .
propertyName ,
50 document . getElementById ( i n p u t I d ) . v a l u e ) ;
51 i f ( r e s u l t a t T e s t R e g e x !== true ) {
52 document . getElementById ( ” error_ ”+i n p u t I d ) . innerHTML = r e s u l t a t T e s t R e g e x
+”<br />” ;
53 } else {
54 document . getElementById ( ” error_ ”+i n p u t I d ) . innerHTML = ” ” ;
55 }
56 } ) ; // f i n du c a l l b a c k //////////////////////////////////////////////
57
58 var inputType = i n p u t S p e c . inputType === u n d e f i n e d ? ” t e x t ” : i n p u t S p e c .
inputType ;
59 var i n p u t S i z e = i n p u t S p e c . i n p u t S i z e === u n d e f i n e d ? ” 10 ” : i n p u t S p e c . i n p u t S i z e
;
60 var l a b e l T e x t = i n p u t S p e c . o b j e t M e t i e r . g e t L a b e l T e x t ( i n p u t S p e c . propertyName ) ;
61
62 // r e t o u r du code HTML de l ’ i n p u t
63 return ”<span c l a s s =\”errorMsg \” i d =\”error_ ”+i n p u t I d+” \”>” + e r r o r M e s s a g e + ”
</span>” +
64 ”<l a b e l f o r =\”” + i n p u t S p e c . propertyName + ” \”>” + l a b e l T e x t + ”</ l a b e l>”
+
65 ”<i nput t y p e =\”” + inputType + ” \” name=\”” + i n p u t S p e c . propertyName
+
66 ” \” i d =\”” + i n p u t I d + ” \” ” + ” v a l u e =\”” + p r o p e r t y V a l u e + ” \” ” +
67 ” s i z e =\”” + i n p u t S i z e + ” \” ” +
68 ” onchange=\”myApp . g u i . p u b l i s h I n p u t C h a n g e ( ’ ” + i n p u t S p e c . formId + ” ’ , ’
” + i n p u t S p e c . propertyName + ” ’ ) \” ” + ” />” ;
69 }]) ;
70
71 /* *
72 * Géné r a t i o n du code HTML de l ’ e n s e m b l e d e s i n p u t s d ’ un f o r m u l a i r e .

69
Rémy Malgouyres, http://malgouyres.org Programmation Web Côté Client, JS et jQuery

73 * @method myApp . g u i . getHtmlFormInputs


74 * @param { O b j e c t } o b j e t M e t i e r i n t a n c e d ’ un module mé t i e r ( par exemple i n s t a n c e
d ’ a d r e s s e , de pe r so nn e . . . ) .
75 * c e t o b j e t d o i t i m p l é menter d e s i n t e r f a c e s pr é c i s e s (
g e t P r o p e r t y ( ) , getModule ( ) , e t c . )
76 * @param { s t r i n g } formId i d du f o r m u l a i r e dans l e q u e l l ’ i n p u t s e r a i n s é r é
77 * @retuern { s t r i n g } l e code HTML d e s t o u s l e s i n p u t s c o r r e s p o n d a n t aux p r o p r i é t
é s de l ’ o b j e t mé t i e r .
78 */
79 myApp . addModule . apply (myApp . gui , [ ” getHtmlFormInputs ” , function ( o b j e t M e t i e r ,
formId ) {
80
81 // Dé f i n i t i o n de l ’ i n t e r f a c e commune aux i n s t a n c e s d e s modules mé t i e r ( a d r e s s e
, personne , e t c . )
82 var metierCommonInstanceMethods = new I n t e r f a c e (
83 [ ” getPropertyList ” , ” getLabelText ” , ” testRegex ” , ” getProperty ” ,
84 ” setP ro pe rty ” , ” hasError ” , ” getErrorMessage ” , ” g e t E r r o r L i s t ” ] ) ;
85
86 var t e s t I n t e r f a c e = metierCommonInstanceMethods . isImplementedBy ( o b j e t M e t i e r ) ;
87 var message ;
88 i f ( t e s t I n t e r f a c e !== true ) {
89 throw new E r r o r ( t e s t I n t e r f a c e ) ;
90 }
91
92 // Ajour du f o r m u l a i r e ”mainForm” au mé d i a t e u r q u i g è r e r a s e s é v é nements .
93 myApp . c t r l . m e d i a t o r I n p u t F i l t e r . addForm ( formId ) ;
94
95 var htmlCode = ” ” ;
96
97 var p r o p e r t y L i s t = o b j e t M e t i e r . g e t P r o p e r t y L i s t ( ) ;
98
99 // Tous l e s i n p u t s s o n t de t y p e t e x t e , donc on p e u t
100 // f a i r e une b o u c l e a u t o m a t i q u e s u r l e s p r o p r i é t é s .
101 for ( var i =0 ; i < p r o p e r t y L i s t . l e n g t h ; i ++){
102 var propertyName = p r o p e r t y L i s t [ i ] ;
103 // l ’ u t i l i s a t e u r ne p e u t pas m o d i f i e r l ’ ID :
104 i f ( propertyName != ” i d ” ) {
105 // Concat é n a t i o n du code HTML de l ’ i n p u t
106 htmlCode += myApp . g u i . getInputCode ( {
107 objetMetier : objetMetier ,
108 propertyName : p r o p e r t y L i s t [ i ] ,
109 labelText : objetMetier . getLabelText ( propertyList [ i ] ) ,
110 formId : formId
111 } ) + ”<br />” ;
112 }
113 }
114
115 // champs cach é r e p r é s e n t a n t l ’ ID de l ’ i n s t a n c e
116 htmlCode += ”<i nput t y p e =\” h i d d e n \” i d =\”” + formId + ” _id \” v a l u e =\”” +
117 o b j e t M e t i e r . g e t P r o p e r t y ( ” i d ” ) + ” \” />” ;
118
119 return htmlCode ;
120 }]) ;

70
Chapitre 5

Exemple d’Application Interactive

5.1 Principe de l’application et analyse fonctionnelle


Notre application, qui possède un modèle constitué d’une collection de personnes, permet (voir
les storyboards sur la figure 5.1) :

• D’afficher la liste des noms de personnes (items) ;

• De sélectionner une personne en cliquant sur l’item correspondant (l’item est alors surli-
gné et les détails concernant cette personne sont affichés) ;

• De modifier les données de la personnes (en l’occurence le nom) en cliquant sur un bouton
”Modifier”.

• D’ajouter une personne ;

• De supprimer la personne sélectionnée.

• d’ajouter, de supprimer ou de modifier une adresse pour la personne sélectionnée.

Comme on peut le voir, nous avons une agrégation entre les personnes et les adresses, une
personne pouvant avoir plusieurs adresses.
En recenssant les événements (clics de boutons d’items, liens) possibles sur les storyboards
de la figure 5.1, on dresse le diagramme de cas d’utilisation représenté sur la figure 5.2.

5.2 Modèle de donnée


Dans notre modèle de données, une classe personne comporte un nom et une composition avec
des instances d’adresse. Nous créons, pour le moment, quelques instances ”en dur”, dans un
tableau personnes, avec chacune une adresse. Une autre propriété selectedPersonne contient
une référence vers l’instance de personne sélectionnée (item surligné et détails affichés).
exemples/ihm/ex00_modelModule.js
1
2 myApp . addModule . apply (myApp, [ ” modele ” , {
3 s e l e c t e d P e r s o n n e : null ,
4 personnes : [ ] ,

71
Rémy Malgouyres, http://malgouyres.org Programmation Web Côté Client, JS et jQuery

(a) Sélection d’une personne (item surligné à gauche)

(b) Ajout d’une adresse pour la personne sélectionnée

(c) Ajout d’une personne

(d) Après ajout d’une personne

Figure 5.1 : Captures d’écran de notre application

72
Chapitre 5 : Exemple d’Application Interactive

Figure 5.2 : Diagramme de cas d’utilisation de notre application avec son IHM

5 }]) ;
6
7 myApp . modele . p e r s o n n e s . push (myApp . m e t i e r . p e r s o n n e . c r e a t e I n s t a n c e ( {
8 i d : ” 0123 a b c d e f ” ,
9 nom : ” Toto l e Hé ro ” ,
10 a d r e s s e : myApp . m e t i e r . a d r e s s e . c r e a t e I n s t a n c e ( {
11 i d : ” 04 a b f 8 5 b c 9 ” ,
12 numeroRue : ”2 b i s ” ,
13 r u e : ”Rue de l ’ a Paix ” ,
14 complementAdresse : ” D a l l e ” ,
15 c o d e P o s t a l : ” 630000 ” ,
16 v i l l e : ” Clermont−Ferrand ” ,
17 pays : ” France 2 ”
18 })
19 }) ) ;
20
21 myApp . modele . p e r s o n n e s . push (myApp . m e t i e r . p e r s o n n e . c r e a t e I n s t a n c e ( {
22 i d : ” 0123 abcd12 ” ,
23 nom : ” T i t i l e t o u t p ’ t i t ” ,
24 a d r e s s e : myApp . m e t i e r . a d r e s s e . c r e a t e I n s t a n c e ( {
25 i d : ” 04 a b f 8 5 b b 5 ” ,
26 numeroRue : ”4 t e r ” ,
27 r u e : ”Rue de l ’ e n f e r ” ,
28 complementAdresse : ” c ’ e s t l e s a u t r e s . . . ” ,
29 c o d e P o s t a l : ” 75000 ” ,
30 v i l l e : ” Ris pas ” ,
31 pays : ” France ”
32 })

73
Rémy Malgouyres, http://malgouyres.org Programmation Web Côté Client, JS et jQuery

33 }) ) ;
34
35 myApp . modele . p e r s o n n e s . push (myApp . m e t i e r . p e r s o n n e . c r e a t e I n s t a n c e ( {
36 i d : ” 0123 abcd01 ” ,
37 nom : ” Toutou c ’ e s t par où ” ,
38 a d r e s s e : myApp . m e t i e r . a d r e s s e . c r e a t e I n s t a n c e ( {
39 i d : ” 04 a b f 8 5 b a 4 ” ,
40 numeroRue : ”1” ,
41 r u e : ” P l a c e de l ’ A l t e r n a t i v e ” ,
42 complementAdresse : ” Pourquoi pas ” ,
43 c o d e P o s t a l : ” 63123 ” ,
44 v i l l e : ” Les Paumiers ” ,
45 pays : ” France ”
46 })
47 }) ) ;

5.3 Pattern Mediator : centraliser les événements


Notre module mediator va nous permettre :

• De découpler l’implémentation de la réaction aux événements utilisateurs (modification


du modèle, mise à jour des vues) de la gestion de ces événements utilisateurs via la
technologie jQuery, qui, de ce fait, se trouve circonscrite à une seule classe (Wrapper).

• D’éliminer les dépendances cycliques entre les modules de notre application ;

• De recenser les événements utilisateurs de manière lisible dans un module centralisé ;

• De provoquer des mises à jour de panneaux de la vue qui observent des propriétés du
modèle.

Contrairement au médiateur spécialisé dans le filtrage des attributs de formulaires décrit


dans la partie 4.2, le module mediator va nous permettre d’exécuter plusieurs callback en
réaction à un même événement (par exemple pour mettre à jour différentes parties de la vue
après une modification du modèle).

exemples/ihm/ex01_mediator.js
1 /* *
2 * Impl é m e n ta ti o n du p a t t e r n ”Mé d i a t o r ” pour l a g e s t i o n d e s é v é nements
utilisateurs ,
3 * e t l a mise à j o u r d e s v u e s ( ou d e s sous−a r b r e s du DOM)
4 */
5 myApp . addModule . apply (myApp . gui , [ ” m e d i a t o r ” , function ( ) {
6
7 /* *
8 * L i s t e d e s é v é nements pour l e s q u e l s une l i s t e de c a l l b a c k s p e u t ê t r e
enregistr ée
9 * @private
10 */
11 var m _ s u b s c r i p t i o n L i s t s ;
12
13 /* *

74
Chapitre 5 : Exemple d’Application Interactive

14 * I n i t i a l i s e l a l i s t e d e s é v é nements , a v e c pour chacun , une l i s t e de


callbacks vide .
15 * @method i n i t
16 */
17 var i n i t = function ( ) {
18 m_subscriptionLists = {
19
20 // Opé r a t i o n s CRUD s u r l e s p e r s o n n e s
21 ” p e r so n ne / re ad ” : [ ] , // L i r e t o u t e s l e s p e r s o n n e s pour ( r e ) o n s t r u i r e l e
modèle
22
23 ” p e r so n ne / u p d a t e ” : [ ] , // v a l i d a t i o n du f o r m u l a i r e de mise à j o u r de l a
p e r s o nn e s é l e c t i o n n é e .
24 ” p e r so n ne / c r e a t e ” : [ ] , // v a l i d a t i o n du f o r m u l a i r e d ’ a j o u t d ’ une p e r s o nn e .
25 ” p e r so n ne / d e l e t e ” : [ ] , // S u p p r e s s i o n d ’ une pe r so nn e
26
27 // Opé r a t i o n s CRUD s u r l e s a d r e s s e s
28 ” a d r e s s e / c r e a t e ” : [ ] , // v a l i d a t i o n du f o r m u l a i r e d ’ a j o u t d ’ une a d r e s s e .
29 ” a d r e s s e / u p d a t e ” : [ ] , // mise à j o u r d ’ une a d r e s s e
30 ” a d r e s s e / d e l e t e ” : [ ] , // S u p p r e s s i o n d ’ une a d r e s s e
31
32 // A c t i o n s U t i l i s a t e u r donnant l i e u à un changement de l e vue
33 ” p e r so n ne / s e l e c t D e t a i l s ” : [ ] , // Sé l e c t i o n d ’ une p e r so nne pour v o i r l e s d
é tails
34 ” p e r so n ne / e d i t ” : [ ] , // c l i c k s u r l a m o d i f i c a t i o n de l a p e r so n ne s é
lectionn ée
35 ” p e r so n ne / s a i s i e ” : [ ] , // c l i c k s u r l a m o d i f i c a t i o n de l a pe r so nne s é
lectionn ée
36
37 ” a d r e s s e / e d i t ” : [ ] , // S u p p r e s s i o n d ’ une a d r e s s e
38 ” a d r e s s e / s a i s i e ” : [ ] , // c l i c k s u r l a m o d i f i c a t i o n de l a p e r s o nn e s é
lectionn ée
39
40 // N o t i f i c a t i o n s de m o d i f i c a t i o n du modèle pour r e q u ê t e AJAX e t /ou mise à
j o u r de l a vue
41 ” p e r so n ne / changed ” : [ ] , // mise à j o u r d ’ une p e r so nne
42 ” p e r so n ne / c r e a t e d ” : [ ] , // mise à j o u r d ’ une p e r so nne
43 ” p e r so n ne / d e t a i l s C h a n g e d ” : [ ] , // Mise à j o u r r e q u i s e du panneau d e s d é
tails
44
45 // N o t i f i c a t i o n s de m o d i f i c a t i o n du modèle pour r e q u ê t e AJAX e t /ou mise à
j o u r de l a vue
46 ” a d r e s s e / changed ” : [ ] , // mise à j o u r d ’ une a d r e s s e
47 ” a d r e s s e / c r e a t e d ” : [ ] , // mise à j o u r d ’ une a d r e s s e
48
49
50 // Demande de r é−e n r e g i s t r e m e n t d ’ é v é nements u t i l i s a t e u r s s u i t e à
r e c o n s t r u c t i o n d ’ é l é ments HTML
51 ” p e r so n ne / h t m l L i s t e I t e m R e b u i l t ” : [ ] , // Ré e n r e g i s t r e m e n t d e s é v é nements de
c l i c k sur l e s items
52 // s u i t e à r e c o n s t r u c t i o n c o m p l è t e du
code HTML d e s i t e m s .
53 ” p e r so n ne / d e t a i l s R e b u i l t ” : [ ] , // Ré e n r e g i s t r e m e n t d e s é v é nements de c l i c k
s u r l e s b o u t o n s ” Supprimer ” , ” M o d i f i e r ”
54 // s u i t e à r e c o n s t r u c t i o n du code HTML
des dé t a i l s .

75
Rémy Malgouyres, http://malgouyres.org Programmation Web Côté Client, JS et jQuery

55
56 };
57 };
58
59 // Appel de l a mé t h o d e d ’ i n i t i a l i s a t i o n
60 init () ;
61
62 /* *
63 * I n t e r f a c e p u b l i q u e du module m e d i a t o r
64 */
65 var p u b l i c I n t e r f a c e M e d i a t o r = {
66
67 /* *
68 * E n r e g i s t r e m e n t d ’ un c a l l b a c k s u r un é v é nement .
69 * I l p e u t y a v o i r p l u s i e u r s c a l l b a c k s s u r un même é v é nement
70 * ( par exemple : mise à j o u r de deux p a r t i e s d i s t i n c t e s de l a vue )
71 * @param { s t r i n g } e v e n t C a t e g é v é nement , q u i d o i t ê t r e un nom de p r o p r i é t é
de m _ s u b s c r i p t i o n L i s t s
72 * @param { f u n c t i o n } c a l l b a c k F u n c t i o n l a f o n c t i o n q u i s e r a a p p e l é e en r é
a c t i o n à l ’ é v é nement .
73 */
74 s u b s c r i b e : function ( eventCateg , c a l l b a c k F u n c t i o n ) {
75 i f ( m _ s u b s c r i p t i o n L i s t s . hasOwnProperty ( eventCateg ) ) {
76 m _ s u b s c r i p t i o n L i s t s [ eventCateg ] . push ( { c a l l b a c k : c a l l b a c k F u n c t i o n } ) ;
77 } else {
78 throw new E r r o r ( ” Cat é g o r i e d ’ é v é nements ” + eventCateg + ” inconnue du m
é diateur ”) ;
79 }
80 },
81
82 /* *
83 * P u b l i c a t i o n d ’ un é v é nement s u r v e n u e t ex é c u t i o n de t o u s l e s c a l l b a c k s
correspondants .
84 * @param { s t r i n g } e v e n t C a t e g é v é nement , q u i d o i t ê t r e un nom de p r o p r i é t é
de m _ s u b s c r i p t i o n L i s t s
85 * @param { O b j e c t } c o n t e x t A r g argument o p t i o n n e l à t r a n s m e t t r e au c a l l b a c k (
exemple : item c l i q u é . . . )
86 */
87 p u b l i s h : function ( eventCateg , c o n t e x t A r g ) {
88 var i ;
89 i f ( m _ s u b s c r i p t i o n L i s t s . hasOwnProperty ( eventCateg ) ) {
90 f or ( i =0 ; i< m _ s u b s c r i p t i o n L i s t s [ eventCateg ] . l e n g t h ; ++i ) {
91 // On a p p e l l e l e c a l l b a k a v e c son
92 m _ s u b s c r i p t i o n L i s t s [ eventCateg ] [ i ] . c a l l b a c k ( c o n te x t Ar g ) ;
93 }
94 } else {
95 throw new E r r o r ( ” Cat é g o r i e d ’ é v é nements ” + eventCateg + ” inconnue du m
é diateur ”) ;
96 }
97 },
98
99 // Ré i n i t i a l i s e l e s l i s t e s de c a l l b a c k s à v i d e .
100 empty : function ( ) {
101 init () ;
102 }
103 };

76
Chapitre 5 : Exemple d’Application Interactive

104
105 return p u b l i c I n t e r f a c e M e d i a t o r ;
106 }() ] ) ;

5.4 Événements concernant les personnes


5.4.1 Enregistrement des événements utilisateurs via jQuery
Tous les événements recensés dans le diagramme de cas d’utilisation (voir la figure 5.2) se
verront ici attribué un gestionnaire qui, généralement, ne fera que publier l’événement auprès de
mediator (partie 5.3). Les éléments HTML constants de la vue (<span>, <button>, <div>, <p>,
etc.) sur lesquels ces événements seront appliqués sont définis dans le fichier HTML principal
décrit dans la partie 5.4.9.
Ces événements utilisateurs doivent parfois être réenregistrés suite à la reconstruction des
éléments HTML concernés. Les événements sont alors détruits (méthodes jQuery.off(), ou
jQuery.empty(), ou encore jQuery.remove()), puis, le code HTML est regénéré, et enfin, les
événements utilisateur sont ré-enregistrés (méthode jQuery.on()).
S’il faut prévoir de ré-enregistrer un gestionnaire d’événement utilisateur, nous allons per-
mettre de déclencher ce ré-enregistrement via le mediator. Ceci permet d’éviter notamment
des problèmes de dépendance cyclique des fonctions JavaScript ou modules, par exemples du
fait que les événements jQuery doivent être initialisés après la génération de la vue.

exemples/ihm/ex02_guiJQueryEventsPersonne.js
1 /* *
2 * Mé t h o d e d ’ i n i t i a l i s a t i o n d e s é v é nements u t i l i s a t e u r s J a v a S c r i p t .
3 * E n r e g i s t r e m e n t d e s g e s t i o n n a i r e s de c e s é v é nements v i a jQuery .
4 */
5 myApp . addModule . apply (myApp . gui , [ ” i n i t J Q u e r y E v e n t s P e r s o n n e ” , function ( ) {
6
7 // ///////////////////////////////////////////////////////
8 // c l i c k s u r l e bouton ” A j o u t e r une p e r s o nn e ” f a i s a n t s o r t i r l e f o r m u l a i r e
9
10 /* *
11 * G e s t i o n n a i r e c l i c k s u r l e bouton f a i s a n t s o r t i r l e f o r m u l a i r e
12 */
13 var c l i c k B o u t o n S a i s i e P e r s o n n e = function ( e v e n t ) {
14 // p u b l i c a t i o n a u p r è s du mé d i a t o r
15 myApp . g u i . m e d i a t o r . p u b l i s h ( ” p e r so n ne / s a i s i e ” , {
16 p e r s o n n e : myApp . modele . s e l e c t e d P e r s o n n e
17 }) ;
18 };
19
20 // E n r e g i s t r e m e n t du Handler du c l i c k pour m o d i f i e r l e s d é t a i l s de l ’ item s é
l e c t i o n n é v i a jQuery
21 $ ( ”#b o u t o n A j o u t e r P e r s o n n e ” ) . on ( ” c l i c k ” , c l i c k B o u t o n S a i s i e P e r s o n n e ) ;
22
23 // ///////////////////////////////////////////////////////
24 // c l i c k s u r l e bouton ” M o d i f i e r l e nom” f a i s a n t s o r t i r l e f o r m u l a i r e
25
26 /* *
27 * G e s t i o n n a i r e c l i c k s u r l e bouton f a i s a n t s o r t i r l e f o r m u l a i r e

77
Rémy Malgouyres, http://malgouyres.org Programmation Web Côté Client, JS et jQuery

28 */
29 var c l i c k B o u t o n M o d i f i e r P e r s o n n e = function ( e v e n t ) {
30
31 // p u b l i c a t i o n a u p r è s du mé d i a t o r
32 myApp . g u i . m e d i a t o r . p u b l i s h ( ” p e r so n ne / e d i t ” , {
33 p e r s o n n e : myApp . modele . s e l e c t e d P e r s o n n e
34 }) ;
35 };
36
37 // ///////////////////////////////////////////////////////
38 // c l i c k s u r l e bouton ” Supprimer l a p e r so nne ” f a i s a n t s o r t i r l e f o r m u l a i r e
39
40 /* *
41 * G e s t i o n n a i r e c l i c k s u r l e bouton f a i s a n t s o r t i r l e f o r m u l a i r e
42 */
43 var c l i c k B o u t o n S u p p r i m e r P e r s o n n e = function ( e v e n t ) {
44 // p u b l i c a t i o n a u p r è s du mé d i a t o r
45 myApp . g u i . m e d i a t o r . p u b l i s h ( ” p e r so n ne / d e l e t e ” , {
46 p e r s o n n e : myApp . modele . s e l e c t e d P e r s o n n e
47 }) ;
48 };
49
50
51 // //////////////////////////////////////////////////////
52 // G e s t i o n n a i r e de s u b m i t f o r m u l a i r e de m o d i f i c a t i o n de p e r so n ne .
53
54 /* *
55 * G e s t i o n n a i r e de l ’ é v é nement s u b m i t du f o r m u l a i r e .
56 * @param { Event } jQuery e v e n t c o r r e s p o n d a n t au h a n d l e r .
57 */
58 var formHandlerModifPersonne = function ( e v e n t ) {
59
60 // É v i t e r d ’ a p p e l e r l ’ ” a c t i o n ” par d é f a u t ( ) s c r i p t PHP, e t c . . . )
61 // du f o r m u l a i r e l o r s du s u b m i t
62 event . preventDefault ( ) ;
63
64 // p u b l i c a t i o n a u p r è s du mé d i a t o r
65 myApp . g u i . m e d ia t o r . p u b l i s h ( ” pe r so nn e / u p d a t e ” , {
66 p e r s o n n e : myApp . modele . s e l e c t e d P e r s o n n e
67 }) ;
68 } // f i n du g e s t i o n n a i r e formHandlerModif ( )
69
70 // E n r e g i s t r e m e n t du Handler du s u b m i t du f o r m u l a i r e v i a jQuery
71 $ ( ”#modifierPersonneForm ” ) . on ( ” s u b m i t ” , formHandlerModifPersonne ) ;
72
73
74 // /////////////////////////////////////////////////////
75 // G e s t i o n n a i r e de s u b m i t f o r m u l a i r e d ’ a j o u t de p e r s o nn e .
76
77 /* *
78 * G e s t i o n n a i r e de l ’ é v é nement s u b m i t du f o r m u l a i r e .
79 * @param { Event } jQuery e v e n t c o r r e s p o n d a n t au h a n d l e r .
80 */
81 var formHandlerAjoutPersonne = function ( e v e n t ) {
82
83 // É v i t e r d ’ a p p e l e r l ’ ” a c t i o n ” par d é f a u t ( ) s c r i p t PHP, e t c . . . )

78
Chapitre 5 : Exemple d’Application Interactive

84 // du f o r m u l a i r e l o r s du s u b m i t
85 event . preventDefault ( ) ;
86
87 // p u b l i c a t i o n a u p r è s du mé d i a t o r
88 myApp . g u i . m e d ia t o r . p u b l i s h ( ” pe r so nn e / c r e a t e ” , {
89 p e r s o n n e : myApp . modele . s e l e c t e d P e r s o n n e
90 }) ;
91 } // f i n du g e s t i o n n a i r e formHandlerAjout ( )
92
93 // E n r e g i s t r e m e n t du Handler du s u b m i t du f o r m u l a i r e v i a jQuery
94 $ ( ”#ajouterPersonneForm ” ) . on ( ” s u b m i t ” , formHandlerAjoutPersonne ) ;
95
96
97 /* *
98 * E n r e g i s t r e l e s é v é nements de c l i c k s s u r l e s b o u t o n s ” M o d i f i e r ” e t ”
Supprimer ”
99 * l a p e r s o nn e s é l e c t i o n n é e .
100 * C e t t e f o n c t i o n d o i t ê t r e i n v o q u é e en c a s de s é l e c t i o n d ’ une n o u v e l l e
p e r so nne
101 * ( r e c o n s t r u c t i o n deu code HTML du panneau d e s d é t a i l s .
102 */
103 var r e g i s t e r B u t t o n C l i c k E v e n t s = function ( ) {
104 // E n r e g i s t r e m e n t du Handler du c l i c k pour m o d i f i e r l e s d é t a i l s de l ’ item s é
l e c t i o n n é v i a jQuery
105 $ ( ”#b o u t o n M o d i f i e r P e r s o n n e ” ) . on ( ” c l i c k ” , c l i c k B o u t o n M o d i f i e r P e r s o n n e ) ;
106 // E n r e g i s t r e m e n t du Handler du c l i c k pour su p p r i m e r l ’ item s é l e c t i o n n é v i a
jQuery
107 $ ( ”#boutonSupprimerPersonne ” ) . on ( ” c l i c k ” , c l i c k B o u t o n S u p p r i m e r P e r s o n n e ) ;
108 }
109
110 // ///////////////////////////////////////////////////////
111 // C l i c k s s u r l e s é l é ments de l a l i s t e d ’ i t e m s
112
113 /* * Mé t h o d e q u i permet de c r é e r un g e s t i o n n a i r e d ’ é v é nement de c l i c k
114 * s u r chaque nom de p e r s o n n e s ( s é l e c t i o n d e s d é t a i l s )
115 * Ces g e s t i o n n a i r e s p u b l i e n t l ’ é v é nnement ” n o u v e l l e p e r s onn e s é l e c t i o n n é e ”
a u p r è s du mé d i a t o r .
116 * @param { i n t } i n d e x i n d i c e de l ’ item pour l e q u e l on e n r e g i s t r e l ’ é v é nement .
117 */
118 var r e g i s t e r H e l p e r S e l e c t D e t a i l s = function ( i n d e x ) {
119 return function ( ) {
120 myApp . g u i . m e d ia t o r . p u b l i s h ( ” pe r so nn e / s e l e c t D e t a i l s ” ,
121 {
122 p e r s o n n e : myApp . modele . p e r s o n n e s [ i n d e x ]
123 }) ;
124 };
125 };
126
127 /* *
128 * E n r e g i s t r e l e s é v é nements j a v a s c r i p t de c l i c k s u r l e s é l é ments de l a l i s t e
129 * ( noms d e s p e r s o n n e s ) .
130 * C e t t e mé t h o d e d o i t ê t r e a p p e l é e l o r s de l a r e g éné r a t i o n du code de l a l i s t e
.
131 * @method r e g i s t e r L i s t e P e r s o n n e s C l i c k s
132 * @param { O b j e c t } c o n t e x t A r g s non u t i l i s é
133 * @return { f u n c t i o n } une f o n c t i o n c a l l b a c k q u i g è r e s l e c l i c k s u r l ’ item

79
Rémy Malgouyres, http://malgouyres.org Programmation Web Côté Client, JS et jQuery

index
134 */
135 var r e g i s t e r L i s t e P e r s o n n e s C l i c k s = function ( c o n t e x t A r g s ) {
136 for ( var i =0 ; i<myApp . modele . p e r s o n n e s . l e n g t h ; ++i ) {
137 $ ( ”#master_ ”+ myApp . modele . p e r s o n n e s [ i ] . g e t I d ( ) ) . on (
138 ” click ” , registerHelperSelectDetails ( i ) ) ;
139 }
140 };
141
142 // E n r e g i s t r e r l e s c l i c k s l o r s de l ’ i n i t i a l i s a t i o n
143 registerButtonClickEvents () ;
144 registerListePersonnesClicks () ;
145
146 // Permet à l a mé t h o d e q u i r e g é nè re t o u t e l a l i s t e d e s i t e m s
147 // de r e c r é er , v i a l e mé d i a t o r , l e s é v é nements ” c l i c k ” s u r l e s i t e m s .
148 myApp . g u i . m e d i a t o r . s u b s c r i b e ( ” p e r so n ne / h t m l L i s t e I t e m R e b u i l t ” ,
registerListePersonnesClicks ) ;
149
150 // Permet à l a mé t h o d e q u i r e g é nè re l e panneau d e s d é t a i l s de r e c r é er ,
151 // v i a l e mé d i a t o r , l e s é v é nements ” c l i c k ” s u r l e s b o u t o n s dans l e panneau d e s
dé t a i l s .
152 myApp . g u i . m e d i a t o r . s u b s c r i b e ( ” p e r so n ne / d e t a i l s R e b u i l t ” ,
registerButtonClickEvents ) ;
153 }]) ;

5.4.2 Mise à jour du panneau des détails


Le panneau des détails de l’item sélectionné doit être mis à jour lors de la modification de
la personne par validation du formulaire, ou lors du changement de l’item sélectionné (click
sur un autre item). dans ce cas, les événements utilisateurs sur les éléments HTML qui sont
générés dynamiquement sur le panneau des détails doivent aussi être reconstruit (événement
personne/detailsRebuilt du mediator).

exemples/ihm/ex03_guiDetailsChanged.js
1 /* *
2 * Dé f i n i t i o n e t e n r e g i s t r e m e n t d e s c a l l b a c k s de mise à j o u r d e s d é t a i l s de l ’
item s é l e c t i o n n é e .
3 */
4 myApp . addModule . apply (myApp . gui , [ ” c a l l b a c k s U p d a t e D e t a i l s ” , function ( ) {
5
6 /* *
7 * Géné r a t i o n du code HTML d e s d é t a i l s de l a p e r so nne s é l e c t i o n n é e .
8 */
9 var getHtmlCodeDetail = function ( ) {
10 var htmlCode = ”<span c l a s s =\” p a n e l \”>” +
11 ”<p><s trong>Nom :</s trong> ” + myApp . modele . s e l e c t e d P e r s o n n e . getNom ( )
+ ”</p>” +
12 ”<button i d =\” b o u t o n M o d i f i e r P e r s o n n e \”>M o d i f i e r</button><br />” +
13 ”<button i d =\” boutonSupprimerPersonne \”>Supprimer</button><br />” +
14 ”<button i d =\” b o u t o n A j o u t e r A d r e s s e \”>A j o u t e r une a d r e s s e</button>” ;
15 f or ( var i n d e x = 0 ; i n d e x < myApp . modele . s e l e c t e d P e r s o n n e . getNbAdre ss es ( ) ;
++i n d e x ) {
16 htmlCode += ”<p>” +

80
Chapitre 5 : Exemple d’Application Interactive

17 myApp . view . a d r e s s e . getHtmlDevelopped (myApp . modele .


selectedPersonne . getAdresse ( index ) )
18 + ”<br /><button i d =\” boutonSupprimerAdresse_ ”
19 + myApp . modele . s e l e c t e d P e r s o n n e . g e t A d r e s s e ( i n d e x ) . g e t P r o p e r t y (
’ id ’ )
20 +” \”>Supprimer l ’ a d r e s s e</button>”
21 + ”<br /><button i d =\” b o u t o n M o d i f i e r A d r e s s e _ ”
22 + myApp . modele . s e l e c t e d P e r s o n n e . g e t A d r e s s e ( i n d e x ) . g e t P r o p e r t y (
’ id ’ )
23 +” \”>M o d i f i e r l ’ a d r e s s e</button>”
24 + ”</p>” ;
25 }
26 htmlCode += ”</span>” ;
27 return htmlCode ;
28 };
29
30 /* *
31 * R e d e s s i n e l e s d é t a i l s d ’ une p e r s o nn e s u i t e à sa s é l e c t i o n ou sa
modification .
32 * @param { O b j e c t } c o n t e x t A r g non u t i l i s é .
33 */
34 var r e p a i n t D e t a i l = function ( c o n te x t Ar g ) {
35
36 $ ( ”#modifierPersonneForm ” ) . empty ( ) ; // Vider l e s i n p u t s e t l e s é v é nements JS
existant
37 $ ( ”#ajouterPersonneForm ” ) . empty ( ) ; // Vider l e s i n p u t s e t l e s é v é nements JS
existant
38 $ ( ”#aj o u t e r A d r e sse Fo r m ” ) . empty ( ) ; // Vider l e s i n p u t s e t l e s é v é nements JS
existant
39 $ ( ”#modifierAdresseForm ” ) . empty ( ) ; // Vider l e s i n p u t s e t l e s é v é nements JS
existant
40
41 $ ( ”#v u e D e t a i l ” ) . empty ( ) ; // Vider l e s d é t a i l s de l ’ item s é l e c t i o n n é
42
43 $ ( ”#v u e D e t a i l ” ) . html ( getHtmlCodeDetail ( ) ) ; // Géné r a t i o n du code HTML
44
45 // Recr é e r l e s é v é nements de c l i c k s s u r l e s b o u t o n s ” m o d i f i e r ” , ” su p p r i m e r ” ,
etc .
46 myApp . g u i . m e d i a t o r . p u b l i s h ( ” p e r so n ne / d e t a i l s R e b u i l t ” ) ;
47 };
48
49 // E n r e g i s t r e m e n t du c a l l b a c k de l ’ é v é nement d é d i é (m. a . j . d e s d é t a i l s )
50 myApp . g u i . m e d i a t o r . s u b s c r i b e ( ” p e r so n ne / d e t a i l s C h a n g e d ” , r e p a i n t D e t a i l ) ;
51 // E n r e g i s t r e m e n t du c a l l b a c k de l ’ é v é nement de mise à j o u r de l a pe r so nn e
52 myApp . g u i . m e d i a t o r . s u b s c r i b e ( ” p e r so n ne / changed ” , r e p a i n t D e t a i l ) ;
53
54 }() ] ) ;

5.4.3 Mise à jour du panneau des items


Le panneau qui affiche la liste des l’items doit être mis à jour lors de la modification de
la personne par validation du formulaire (le nom de la personne peut changer), ou lors du
changement de l’item sélectionné, celui-ci étant surligné.
En cas de changement de l’item sélectionné, la propriété selectedPersonne du modèle sera

81
Rémy Malgouyres, http://malgouyres.org Programmation Web Côté Client, JS et jQuery

modifiée, et le rafraîchissement du panneau des détails sera ensuite provoqué.


Lors de la création d’une nouvelle personne, celle-ci sera automatiquement sélectionnée.

exemples/ihm/ex04_guiPersonneChanged.js
1 /* *
2 * Dé f i n i t i o n e t abonnement d e s c a l l b a c k s de mise à j o u r de l a
3 * l i s t e c l i c k a b l e d e s items , s o i t l o r s de l a m o d i f i c a t i o n
4 * du modèle , s o i t l o r s du changement de p e r so n ne s é l e c t i o n n é e .
5 */
6 myApp . addModule . apply (myApp . gui , [ ” c a l l b a c k s M a i n L i s t U p d a t e ” , function ( ) {
7
8 /* *
9 * A c t i v e ou d é s a c t i v e l e s u r l i g n a g e ( s t y l e CSS) d ’ un item de l a l i s t e .
10 * @param { pe r so nne } p e r so n ne item de l a l i s t e à m o d i f i e r ( v i a l ’ ID de l ’ é l é
ment HTML) .
11 * @param { b o o l e a n } h i l g h l i g h t e d t r u e s i on d o i t s u r l i g n e r , f a l s e pour
r e m e t t r e l e s t y l e par d é f a u t .
12 */
13 var s e t H i g h l i g h t e d = function ( personne , h i g h l i g h t e d ) {
14 if ( highlighted ){
15 // Mettre l e s t y l e s u r l i g n é s u r l ’ item de l a l i s t e
16 $ ( ”#master_ ”+ p e r s o n n e . g e t I d ( ) ) . c s s ( ”background−color ” , ”#333” )
17 . c s s ( ” color ” , ”#e e e ” )
18 . c s s ( ”border−r a d i u s ” , ”4 px ” )
19 . c s s ( ”padding” , ”2 px ” ) ;
20 } else {
21 // Remettre l e s t y l e normal s u r l ’ item de l a l i s t e
22 $ ( ”#master_ ”+ p e r s o n n e . g e t I d ( ) ) . c s s ( ”background−color ” , ”#e e e ” )
23 . c s s ( ” color ” , ”#333” )
24 . c s s ( ”border−r a d i u s ” , ”4 px ” )
25 . c s s ( ”padding” , ”2 px ” ) ;
26 }
27 }
28
29 /* *
30 * Géné r a t i o n du code HTML de l a l i s t e de p e r s o n n e s
31 */
32 var g e t H t m l C o d e L i s t e P e r s o n n e s = function ( ) {
33 var htmlCode = ” ” ;
34 f or ( i =0 ; i<myApp . modele . p e r s o n n e s . l e n g t h ; ++i ) {
35 htmlCode +=
36 ”<p i d =\”master_ ”+ myApp . modele . p e r s o n n e s [ i ] . g e t I d ( ) + ” \”>” +
37 ”<s trong>Nom :</s trong> ” + myApp . modele . p e r s o n n e s [ i ] . getNom ( ) + ”</p>” ;
38 }
39 return htmlCode ;
40 };
41
42 /* *
43 * R a f f r a i c h i s s e m e n t ( ou a f f i c h a g e ) de t o u t e l a vue .
44 * @param c o n t e x t A r g non u t i l i s é .
45 */
46 var r e p a i n t V u e = function ( c o nt e x tA r g ) {
47
48 $ ( ”#l i s t e P e r s o n n e s ” ) . empty ( ) ; // Vider l a l i s t e e t s e s é v é nements
49 $ ( ”#l i s t e P e r s o n n e s ” ) . html ( g e t H t m l C o d e L i s t e P e r s o n n e s ( ) ) ; // a f f i c h e r
50

82
Chapitre 5 : Exemple d’Application Interactive

51 // A p p l i q u e r l e s t y l e par d é f a u t s u r t o u s l e s i t e m s
52 for ( var i =0 ; i < myApp . modele . p e r s o n n e s . l e n g t h ; ++i ) {
53 s e t H i g h l i g h t e d (myApp . modele . p e r s o n n e s [ i ] , f a l s e ) ;
54 }
55 // S u r l i g n e r l ’ item s é l e c t i o n n é
56 s e t H i g h l i g h t e d (myApp . modele . s e l e c t e d P e r s o n n e , true ) ;
57
58 // Recr é e r l e s é v é nements de c l i c k s s u r l e s i t e m s de l a l i s t e
59 myApp . g u i . m e d ia t o r . p u b l i s h ( ” pe r so nn e / h t m l L i s t e I t e m R e b u i l t ” ) ;
60 };
61
62 /* *
63 * Changer l ’ item s é l e c t i o n n é en r é a c t i o n à un c l i c k .
64 * @param { O b j e c t } c o n t e x t A r g argument i n d i q u a n t l a n o u v e l l e p e r s o nn e s é
lectionn ée .
65 * @param { pe r so nne } c o n t e x t A r g . pe r so nn e n o u v e l l e p e r so nne s é l e c t i o n n é e .
66 */
67 var s e l e c t P e r s o n n e = function ( c o nt e x tA r g ) {
68 // Supprimer l e s u r l i g n a g e de l ’ a n c i e n n e p e r so n ne s é l e c t i o n n é e
69 s e t H i g h l i g h t e d (myApp . modele . s e l e c t e d P e r s o n n e , f a l s e ) ;
70
71 // Changer l ’ item s é l e c t i o n n é
72 myApp . modele . s e l e c t e d P e r s o n n e = c o n te x tA r g . p e r s o n n e ;
73
74 // Me ttr e l e s t y l e s u r l i g n é s u r l ’ item s é l e c t i o n n é de l a l i s t e
75 s e t H i g h l i g h t e d (myApp . modele . s e l e c t e d P e r s o n n e , true ) ;
76
77 // Provoquer l a mise à j o u r du panneau d e s d é t a i l s
78 myApp . g u i . m e d i a t o r . p u b l i s h ( ” p e r so n ne / d e t a i l s C h a n g e d ” , {
79 p e r s o n n e : myApp . modele . s e l e c t e d P e r s o n n e
80 }) ;
81 };
82
83 /* *
84 * Changer l ’ item s é l e c t i o n n é s u i t e à c r é a t i o n d ’ une p e r s o nn e e t mise à j o u r
de l a vue .
85 * @param { O b j e c t } c o n t e x t A r g argument i n d i q u a n t l a n o u v e l l e p e r s o nn e s é
lectionn ée .
86 * @param { pe r so nne } c o n t e x t A r g . pe r so nn e n o u v e l l e p e r so nne s é l e c t i o n n é e .
87 */
88 var s e l e c t P e r s o n n e A n R e p a i n t = function ( c o nt e x tA r g ) {
89 s e l e c t P e r s o n n e ( c o n t e x t Ar g ) ;
90 repaintVue ( ) ;
91 }
92
93 // E n r e g i s t r e m e n t du c a l l b a c k de m o d i f i c a t i o n de l a p e r s o nn e
94 myApp . g u i . m e d i a t o r . s u b s c r i b e ( ” p e r so n ne / changed ” , r e p a i n t V u e ) ;
95 // E n r e g i s t r e m e n t du c a l l b a c k de c r é a t i o n de l a p e r s o nn e
96 myApp . g u i . m e d i a t o r . s u b s c r i b e ( ” p e r so n ne / c r e a t e d ” , s e l e c t P e r s o n n e A n R e p a i n t ) ;
97 // E n r e g i s t r e m e n t du c a l l b a c k de s é l e c t i o n d ’ une n o u v e l l e pe r so nne .
98 myApp . g u i . m e d i a t o r . s u b s c r i b e ( ” p e r so n ne / s e l e c t D e t a i l s ” , s e l e c t P e r s o n n e ) ;
99 }() ] ) ;

83
Rémy Malgouyres, http://malgouyres.org Programmation Web Côté Client, JS et jQuery

5.4.4 Bouton ”Supprimer”


Lorsque l’utilisateur clique sur ”Supprimer”, la personne sélectionnée est supprimée du modèle.
Une nouvelle personne est sélectionnée (personne par défaut) et la vue est réinitialisée.
exemples/ihm/ex07_guiBoutonSupprimerPersonne.js
1 /* *
2 * Dé f i n i t i o n e t e n r e g i s t r e m e n t d e s c a l l b a c k s a p p e l é s à g é r e r l e c l i c s u r l e
bouton
3 * ” m o d i f i e r ” l a pe r so nn e s é l e c t i o n n é e .
4 */
5 myApp . addModule . apply (myApp . gui , [ ” c a l l b a c k s C l i c k S u p p r i m e r ” , function ( ) {
6
7 /* *
8 * C a l l b a c k q u i supprime l a pe r so nne p a s s é e dans l ’ o b j e t p a s s é en argument .
9 * @param { O b j e c t } c o n t e x t A r g argument i n d i q u a n t l a p e r s o nn e à su p p r i m e r .
10 * @param { pe r so nne } c o n t e x t A r g . pe r so nn e r é f é r e n c e de l ’ i n s t a n c e de p e r so n ne à
su p p r i m e r dans l e modèle .
11 */
12 var d e l e t e P e r s o n n e = function ( c o nt e x tA r g ) {
13 // I n d i c e dans l e t a b l e a u de l a p e r so n ne à su p p r i m e r .
14 var i n d e x S e l e c t e d P e r s o n n e = myApp . modele . p e r s o n n e s . indexOf ( c on t e xt A r g .
personne ) ;
15 // S u p p r e s s i o n de l a p e r s o nn e dans l e modèle
16 myApp . modele . p e r s o n n e s . s p l i c e ( i n d e x S e l e c t e d P e r s o n n e , 1 ) ;
17 // Personne s é l e c t i o n n é e par d é f a u t
18 myApp . modele . s e l e c t e d P e r s o n n e = myApp . modele . p e r s o n n e s [ 0 ] ;
19
20 // Provoquer l a mise à j o u r de l a vue :
21 myApp . g u i . m e d i a t o r . p u b l i s h ( ” p e r so n ne / changed ” , {
22 p e r s o n n e : myApp . modele . s e l e c t e d P e r s o n n e
23 }) ;
24 }
25
26 // E n r e g i s t r e m e n t du c a l l b a c k
27 myApp . g u i . m e d i a t o r . s u b s c r i b e ( ” p e r so n ne / d e l e t e ” , d e l e t e P e r s o n n e ) ;
28
29 } ( ) ] ) ;

5.4.5 Bouton ”Modifier” et affichage du formulaire


Lorsque l’utilisateur clique sur ”Modifier”, le formulaire doit être affiché avec les données de la
personnes dans les inputs.
exemples/ihm/ex06_guiBoutonModifierPersonne.js
1 /* *
2 * Dé f i n i t i o n e t e n r e g i s t r e m e n t d e s c a l l b a c k s a p p e l é s à g é r e r l e c l i c s u r l e
bouton
3 * ” m o d i f i e r ” l a pe r so nn e s é l e c t i o n n é e .
4 */
5 myApp . addModule . apply (myApp . gui , [ ” c a l l b a c k s C l i c k M o d i f i e r P e r s o n n e ” , function ( ) {
6
7 /* *
8 * Géné r a t i o n du code HTML du f o r m u l a i r e de m o d i f i c a t i o n de l a p e r so nne s é
lectionn ée .

84
Chapitre 5 : Exemple d’Application Interactive

9 */
10 var getHtmlFormInputs = function ( ) {
11 return ”<span s t y l e =\”width :360 px ; display : i n l i n e −b l o c k ; vertical −align :
top ; \ ”>” +
12 myApp . g u i . getHtmlFormInputs (myApp . modele . s e l e c t e d P e r s o n n e , ”
modifierPersonneForm ” ) +
13 ”<l a b e l></ l a b e l><i nput t y p e =\” s u b m i t \” v a l u e =\” V a l i d e r \”></ i nput>” +
14 ”</span>” ;
15 }
16
17 /* *
18 * C a l l b a c k d ’ A f f i c h a g e ( v i a l e DOM) du f o r m u l a i r e dans l ’ é l é ment d ’ ID ”
modifierPersonneForm ”
19 * @param { O b j e c t } c o n t e x t A r g non u t i l i s é .
20 */
21 var r e p a i n t F o r m I n p u t s = function ( c o n te x t Ar g ) {
22 $ ( ”#modifierPersonneForm ” ) . empty ( ) ; // Vider l e s i n p u t s e t l e s é v é nements JS
existant
23 $ ( ”#ajouterPersonneForm ” ) . empty ( ) ; // Vider l e s i n p u t s e t l e s é v é nements JS
existant
24 $ ( ”#aj o u t e r A d r e sse Fo r m ” ) . empty ( ) ; // Vider l e s i n p u t s e t l e s é v é nements JS
existant
25 $ ( ”#modifierAdresseForm ” ) . empty ( ) ; // Vider l e s i n p u t s e t l e s é v é nements JS
existant
26
27
28 $ ( ”#modifierPersonneForm ” ) . append ( getHtmlFormInputs ( ) ) ; // a j o u t e r l e s
nouveaux i n p u t s
29 };
30
31 // E n r e g i s t r e m e n t du c a l l b a c k
32 myApp . g u i . m e d i a t o r . s u b s c r i b e ( ” p e r so n ne / e d i t ” , r e p a i n t F o r m I n p u t s ) ;
33
34 }() ] ) ;

5.4.6 Bouton ”Ajouter une personne”


Lorsque l’utilisateur clique sur ”Ajouter une personne”, le formulaire doit être affiché avec les
valeurs par défaut (typiquement des champs vides) dans les inputs.
Pour cela, on utilise la possibilité offerte par la fabrique de nos modules métier (partie 3.4)
de créer une objet par défaut en passant null en argument de la fabrique. Ceci permet de ne
pas générer de messages d’erreur en cas de champs obligatoire initialement vide.
Après validation du formulaire, la personne est ajoutée dans le modèle, elle est automati-
quement sélectionnée, et la vue est mise à jour.
exemples/ihm/ex05_guiBoutonAjouterPersonne.js
1 /* *
2 * Dé f i n i t i o n e t e n r e g i s t r e m e n t d e s c a l l b a c k s a p p e l é s à g é r e r l e c l i c s u r l e
bouton
3 * ” m o d i f i e r ” l a pe r so nn e s é l e c t i o n n é e .
4 */
5 myApp . addModule . apply (myApp . gui , [ ” c a l l b a c k s C l i c k A j o u t e r ” , function ( ) {
6
7 /* *

85
Rémy Malgouyres, http://malgouyres.org Programmation Web Côté Client, JS et jQuery

8 * Géné r a t i o n du code HTML du f o r m u l a i r e de m o d i f i c a t i o n de l a p e r so nne s é


lectionn ée .
9 */
10 var getHtmlFormInputs = function ( ) {
11 return ”<span s t y l e =\”width :360 px ; display : i n l i n e −b l o c k ; vertical −align :
top ; \ ”>” +
12 ”<s trong s t y l e =\”width : 360 px ; display : i n l i n e −b l o c k ; text −align :
c e n t e r ; padding : 15 px ; \ ”>S a i s i e d ’ une n o u v e l l e p e r so n ne</s trong>
” +
13 myApp . g u i . getHtmlFormInputs (myApp . m e t i e r . p e r s o n n e . c r e a t e I n s t a n c e (
null ) , ” ajouterPersonneForm ” ) +
14 ”<l a b e l></ l a b e l><i nput t y p e =\” s u b m i t \” v a l u e =\” V a l i d e r \”></ i nput>” +
15 ”</span>” ;
16 }
17
18 /* *
19 * C a l l b a c k d ’ A f f i c h a g e ( v i a l e DOM) du f o r m u l a i r e dans l ’ é l é ment d ’ ID ”
mainForm”
20 * @param { O b j e c t } c o n t e x t A r g non u t i l i s é .
21 */
22 var r e p a i n t F o r m I n p u t s = function ( c o n te x t Ar g ) {
23 $ ( ”#modifierPersonneForm ” ) . empty ( ) ; // Vider l e s i n p u t s e t l e s é v é nements JS
existant
24 $ ( ”#ajouterPersonneForm ” ) . empty ( ) ; // Vider l e s i n p u t s e t l e s é v é nements JS
existant
25 $ ( ”#aj o u t e r A d r e sse Fo r m ” ) . empty ( ) ; // Vider l e s i n p u t s e t l e s é v é nements JS
existant
26 $ ( ”#modifierAdresseForm ” ) . empty ( ) ; // Vider l e s i n p u t s e t l e s é v é nements JS
existant
27
28 $ ( ”#ajouterPersonneForm ” ) . append ( getHtmlFormInputs ( ) ) ; // a j o u t e r l e s
nouveaux i n p u t s
29 };
30
31 // E n r e g i s t r e m e n t du c a l l b a c k
32 myApp . g u i . m e d i a t o r . s u b s c r i b e ( ” p e r so n ne / s a i s i e ” , r e p a i n t F o r m I n p u t s ) ;
33
34 }() ] ) ;

5.4.7 Validation du formulaire de modification


Lors de la validation (événement submit) du formulaire de modification, les données de la
personne sélectionnée doivent être mises à jour à partir des valeurs saisies dans le formulaire.
Les panneaux potentiellement impactés (liste des items, panneau des détails) sont alors mis à
jour.

exemples/ihm/ex09_guiModifierPersonneFormValidate.js
1 /* *
2 * Dé f i n i t i o n e t e n r e g i s t r e m e n t du c a l l b a c k r é a g i s s s a n t à l a v a l i d a t i o n ( s u b m i t )
3 * du f o r m u l a i r e de m o d i f i c a t i o n d ’ une p e r so nne .
4 */
5 myApp . addModule . apply (myApp . gui , [ ” c a l l b a c k s V a l i d a t e M o d i f i e r F o r m ” , function ( ) {
6 // Fo r m u l a i r e de m o d i f i c a t i o n d ’ une p e r s o nn e
7

86
Chapitre 5 : Exemple d’Application Interactive

8 /* *
9 * M o d i f i e l e modèle à p a r t i r d e s donn é e s s a i s i e s dans l e f o r m u l a i r e
10 */
11 var updateModel = function ( ) {
12
13 // 1) Mise à j o u r d e s donn é e s du modèle
14 // à p a r t i r d e s v a l e u r s d e s i n p u t s du f o r m u l a i r e
15 var propertyName ,
16 inputId ;
17 // Pour chaque p r o p r i é t é ( chaque i n p u t du f o r m u l a i r e )
18 f or ( var j =0 ; j< myApp . m e t i e r . p e r s o n n e . g e t P r o p e r t y L i s t ( ) . l e n g t h ; ++j ) {
19 propertyName = myApp . m e t i e r . p e r s o n n e . g e t P r o p e r t y L i s t ( ) [ j ] ;
20 i f ( propertyName != ” i d ” ) {
21 // c a l c u l de l ’ ID de l ’ i n p u t
22 i n p u t I d = myApp . g u i . g e t I n p u t I d ( {
23 propertyName : propertyName ,
24 formId : ” modifierPersonneForm ”
25 }) ;
26 // M o d i f i c a t i o n de l a p r o p r i é t é de l a p e r s o nn e
27 // a v e c l a v a l e u r s a i s i e dans l ’ i n p u t .
28 myApp . modele . s e l e c t e d P e r s o n n e . s e t P r o p e r t y ( propertyName ,
29 document . getElementById ( i n p u t I d ) . v a l u e
30 );
31
32 }
33 }
34 // Provoquer l a mise à j o u r d e s é l é ments de l a vue o b s e r v a n t l a pe r so nn e
35 myApp . g u i . m e d i a t o r . p u b l i s h ( ” p e r so n ne / changed ” , {
36 p e r s o n n e : null
37 }) ;
38 };
39
40 // E n r e g i s t r e m e n t du c a l l b a c k de l ’ é v é nement de v a l i d a t i o n du f o r m u l a i r e
41 myApp . g u i . m e d i a t o r . s u b s c r i b e ( ” p e r so n ne / u p d a t e ” , updateModel ) ;
42
43 }() ] ) ;

5.4.8 Validation du formulaire d’ajout d’une personne


Lors de la validation (événement submit) du formulaire d’ajout, une personne doit être ajoutée
au modèle à partir des valeurs saisies dans le formulaire. Les panneaux potentiellement impactés
(liste des items, panneau des détails) sont alors mis à jour.

exemples/ihm/ex08_guiAjouterPersonneFormValidate.js
1 /* *
2 * Dé f i n i t i o n e t e n r e g i s t r e m e n t du c a l l b a c k r é a g i s s s a n t à l a v a l i d a t i o n ( s u b m i t )
3 * du f o r m u l a i r e de m o d i f i c a t i o n d ’ une p e r so nne .
4 */
5 myApp . addModule . apply (myApp . gui , [ ” c a l l b a c k s V a l i d a t e A j o u t e r F o r m ” , function ( ) {
6
7 /* *
8 * M o d i f i e l e modèle à p a r t i r d e s donn é e s s a i s i e s dans l e f o r m u l a i r e
9 */
10 var updateModel = function ( ) {

87
Rémy Malgouyres, http://malgouyres.org Programmation Web Côté Client, JS et jQuery

11 // 1) Mise à j o u r d e s donn é e s du modèle


12 // à p a r t i r d e s v a l e u r s d e s i n p u t s du f o r m u l a i r e
13 var propertyName ,
14 inputId ;
15
16 // Ajout d ’ un p e r so nne v i d e dans l a c o l l e c t i o n
17 var n o u v e l l e P e r s o n n e = myApp . m e t i e r . p e r s o n n e . c r e a t e I n s t a n c e ( null ) ;
18 myApp . modele . p e r s o n n e s . push ( n o u v e l l e P e r s o n n e ) ;
19
20 // Pour chaque p r o p r i é t é ( chaque i n p u t du f o r m u l a i r e )
21 f or ( var j =0 ; j< myApp . m e t i e r . p e r s o n n e . g e t P r o p e r t y L i s t ( ) . l e n g t h ; ++j ) {
22 propertyName = myApp . m e t i e r . p e r s o n n e . g e t P r o p e r t y L i s t ( ) [ j ] ;
23 i f ( propertyName != ” i d ” ) {
24 // c a l c u l de l ’ ID de l ’ i n p u t
25 i n p u t I d = myApp . g u i . g e t I n p u t I d ( {
26 propertyName : propertyName ,
27 formId : ” ajouterPersonneForm ”
28 }) ;
29 // M o d i f i c a t i o n de l a p r o p r i é t é de l a p e r s o nn e
30 // a v e c l a v a l e u r s a i s i e dans l ’ i n p u t .
31 n o u v e l l e P e r s o n n e . s e t P r o p e r t y ( propertyName ,
32 document . getElementById ( i n p u t I d ) . v a l u e
33 );
34
35 }
36 }
37
38 // Provoquer l a s é l e c t i o n de l a n o u v e l l e p e r so n ne ( e t par s u i t e l a mise à
j o u r de l a vue )
39 myApp . g u i . m e d i a t o r . p u b l i s h ( ” p e r so n ne / c r e a t e d ” , {
40 personne : nouvellePersonne
41 }) ;
42 };
43
44 // E n r e g i s t r e m e n t du c a l l b a c k de l ’ é v é nement de v a l i d a t i o n du f o r m u l a i r e
45 myApp . g u i . m e d i a t o r . s u b s c r i b e ( ” p e r so n ne / c r e a t e ” , updateModel ) ;
46
47 }() ] ) ;

5.4.9 Code HTML de la vue et invocation des méthodes


Il faut surtout penser à inclure jquery.js le plus tard possible et à invoquer la méthode
d’enregistrement des événements utilisateurs après la génération de la vue, qui crée les éléments
HTML sur lesques on applique ces événements.

exemples/ihm/ex10_demoIHM.html
1 <! doctype HTML>
2 <html l a n g=” f r ”>
3 <head>
4 <meta c h a r s e t=”UTF−8” />
5 <t i t l e>A p p l i c a t i o n i n t e r a c t i v e</ t i t l e>
6 <l i nk r e l=” s t y l e s h e e t ” h r e f=” b a s i c S t y l e . c s s ” />
7 </head>
8 <body>

88
Chapitre 5 : Exemple d’Application Interactive

9 <s c r i p t s r c=” . / m o d u l e s M e t i e r P r o t o t y p e . j s ”></s c r i p t>


10 <s c r i p t s r c=” . / m e d i a t o r I n p u t F i l t e r . j s ”></s c r i p t>
11 <s c r i p t s r c=” . / f o r m s G u i P r o t o t y p e . j s ”></s c r i p t>
12 <s c r i p t s r c=” . / i n t e r f a c e I m p l e m e n t a t i o n . j s ”></s c r i p t>
13 <s c r i p t s r c=” . / personneModule . j s ”></s c r i p t>
14 <s c r i p t s r c=” . / modelModule . j s ”></s c r i p t>
15 <s c r i p t s r c=” . / m e d i a t o r . j s ”></s c r i p t>
16 <s c r i p t s r c=” . / g u i B o u t o n M o d i f i e r P e r s o n n e . j s ”></s c r i p t>
17 <s c r i p t s r c=” . / guiBoutonSupprimerPersonne . j s ”></s c r i p t>
18 <s c r i p t s r c=” . / g u i B o u t o n A j o u t e r P e r s o n n e . j s ”></s c r i p t>
19 <s c r i p t s r c=” . / g u i B o u t o n A j o u t e r A d r e s s e . j s ”></s c r i p t>
20 <s c r i p t s r c=” . / g u i B o u t o n M o d i f i e r A d r e s s e . j s ”></s c r i p t>
21 <s c r i p t s r c=” . / guiBoutonSuppri merAdresse . j s ”></s c r i p t>
22 <s c r i p t s r c=” . / g u i M o d i f i e r P e r s o n n e F o r m V a l i d a t e . j s ”></s c r i p t>
23 <s c r i p t s r c=” . / g u i A j o u t e r P e r s o n n e F o r m V a l i d a t e . j s ”></s c r i p t>
24 <s c r i p t s r c=” . / g u i A j o u t e r A d r e s s e F o r m V a l i d a t e . j s ”></s c r i p t>
25 <s c r i p t s r c=” . / g u i M o d i f i e r A d r e s s e F o r m V a l i d a t e . j s ”></s c r i p t>
26 <s c r i p t s r c=” . / g u i D e t a i l s C h a n g e d . j s ”></s c r i p t>
27 <s c r i p t s r c=” . / guiPersonneChanged . j s ”></s c r i p t>
28
29 <!−− Code HTML de l a vue −− S t r u c t u r e g é né r a l e de l a page HTML −−>
30
31 <button i d=” b o u t o n A j o u t e r P e r s o n n e ”>A j o u t e r une p e r s o n n e</button><br />
32 <span i d=” l i s t e P e r s o n n e s ” c l a s s=” p a n e l ”></span>
33 <span c l a s s=” p a n e l ”>
34 <span i d=” v u e D e t a i l ”>
35 </span><br /><br />
36 </span>
37 <span i d=”spanMainForm” c l a s s=” p a n e l ”>
38 <form i d=” ajouterPersonneForm ” method=” p o s t ” ></form>
39 <form i d=” modifierPersonneForm ” method=” p o s t ” ></form>
40 <form i d=” a j o u te r A d r e sse Fo r m ” method=” p o s t ” ></form>
41 <form i d=” modifierAdresseForm ” method=” p o s t ” ></form>
42 </span>
43
44 <!−− I n c l u s i o n de jQuery l e p l u s t r a d p o s s i b l e −−>
45 <s c r i p t s r c=” . / j q u e r y . j s ”></s c r i p t>
46 <s c r i p t s r c=” . / guiJQueryEventsPersonne . j s ”></s c r i p t>
47 <s c r i p t s r c=” . / g u i J Q u e r y E v e n t s A d r e s s e . j s ”></s c r i p t>
48
49 <!−− Ajout d ’ un main e t ex é c u t i o n −−>
50 <s c r i p t>
51 /* *
52 * Sé r i e d ’ i n s t r u c t i o n s e f f e c t u é e s pour i n i t i a l i s e r l ’ a p p l i c a t i o n /
53 * @method mainFunction
54 * @augments myApp
55 */
56 myApp . addModule ( ” mainFunction ” , function ( ) {
57
58 // Personne s é l e c t i o n n é e par d é f a u t
59 myApp . modele . s e l e c t e d P e r s o n n e = myApp . modele . p e r s o n n e s [ 0 ] ;
60
61 // Provoquer l e p r e m i e r a f f i c h a g e de l a vue :
62 myApp . g u i . m e d ia t o r . p u b l i s h ( ” pe r so nn e / changed ” , {
63 p e r s o n n e : myApp . modele . s e l e c t e d P e r s o n n e
64 }) ;

89
Rémy Malgouyres, http://malgouyres.org Programmation Web Côté Client, JS et jQuery

65
66 // E n r e g i s t r e m e n t d e s é v é nements u t i l i s a t e u r s g é r é s par jQuery
67 myApp . g u i . i n i t J Q u e r y E v e n t s P e r s o n n e ( ) ;
68 myApp . g u i . i n i t J Q u e r y E v e n t s A d r e s s e ( ) ;
69
70 }) ;
71
72 // ///////////////////////////////////////////////////
73 // Exé c u t i o n du Main a v e c un t e s t d ’ e x c e p t i o n
74 // t r y {
75 // Exé c u t i o n de l a mé t h o d e mainFunction
76 myApp . mainFunction ( ) ;
77 // } c a t c h ( e ) {
78 // a l e r t ( e . message ) ;
79 // }
80 </s c r i p t>
81 </body>
82 </html>

5.5 Événements concernant les Adresses


5.5.1 Enregistrement des événements utilisateurs via jQuery
De même que pour les personnes, l’utilisation de jQuery est limitée à un module Wrapper, qui
va définir tous les handler.
Comme il peut y avoir plusieurs adresses, dont les éléments HTML sont générés dynami-
quement, sur le panneau des détails, les événements concernant les adresses doivent pouvoir
être reconstruits dans le cas d’une reconstruction du panneau des détails de la vue (événement
personne/detailsRebuilt du mediator. De plus, nous devons créer un handler pour chacune
des adresses de la personne sélectionnée. Ces handler seront créés grâce à des helpers.

exemples/ihm/ex11_guiJQueryEventsAdresse.js
1 /* *
2 * Mé t h o d e d ’ i n i t i a l i s a t i o n d e s é v é nements u t i l i s a t e u r s J a v a S c r i p t .
3 * E n r e g i s t r e m e n t d e s g e s t i o n n a i r e s de c e s é v é nements v i a jQuery .
4 */
5 myApp . addModule . apply (myApp . gui , [ ” i n i t J Q u e r y E v e n t s A d r e s s e ” , function ( ) {
6
7 /* *
8 * G e s t i o n n a i r e c l i c k s u r l e bouton f a i s a n t s o r t i r l e f o r m u l a i r e
9 */
10 var c l i c k B o u t o n S a i s i e A d r e s s e = function ( e v e n t ) {
11 // p u b l i c a t i o n a u p r è s du mé d i a t o r
12 myApp . g u i . m e d i a t o r . p u b l i s h ( ” a d r e s s e / s a i s i e ” , {
13 p e r s o n n e : myApp . modele . s e l e c t e d P e r s o n n e
14 }) ;
15 };
16
17 /* * Mé t h o d e q u i permet de c r é e r un g e s t i o n n a i r e d ’ é v é nement de c l i c k
18 * du bouton de s u p p r e s s i o n s u r chaque a d r e s s e de l a p e r so nne s é l e c t i o n n é e .
19 * Ces g e s t i o n n a i r e s p u b l i e n t l ’ é v é nnement ” n o u v e l l e p e r so nne s é l e c t i o n n é e ”
a u p r è s du mé d i a t o r .

90
Chapitre 5 : Exemple d’Application Interactive

20 * @param { i n t } i n d e x i n d i c e de l ’ a d r e s s e pour l e q u e l on e n r e g i s t r e l ’ é v é
nement .
21 */
22 var r e g i s t e r H e l p e r S u p p r i m e r A d r e s s e = function ( i n d e x ) {
23 return function ( ) {
24 myApp . g u i . m e d ia t o r . p u b l i s h ( ” a d r e s s e / d e l e t e ” ,
25 {
26 p e r s o n n e : myApp . modele . s e l e c t e d P e r s o n n e ,
27 a d r e s s e : myApp . modele . s e l e c t e d P e r s o n n e . g e t A d r e s s e ( i n d e x )
28 }) ;
29 };
30 };
31
32 /* * Mé t h o d e q u i permet de c r é e r un g e s t i o n n a i r e d ’ é v é nement de c l i c k
33 * du bouton de s u p p r e s s i o n s u r chaque a d r e s s e de l a p e r s o nn e s é l e c t i o n n é e .
34 * Ces g e s t i o n n a i r e s p u b l i e n t l ’ é v é nnement ” n o u v e l l e p e r s onn e s é l e c t i o n n é e ”
a u p r è s du mé d i a t o r .
35 * @param { i n t } i n d e x i n d i c e de l ’ a d r e s s e pour l e q u e l on e n r e g i s t r e l ’ é v é nement
.
36 */
37 var r e g i s t e r H e l p e r M o d i f i e r A d r e s s e = function ( i n d e x ) {
38 return function ( ) {
39 myApp . g u i . m e d ia t o r . p u b l i s h ( ” a d r e s s e / e d i t ” ,
40 {
41 p e r s o n n e : myApp . modele . s e l e c t e d P e r s o n n e ,
42 a d r e s s e : myApp . modele . s e l e c t e d P e r s o n n e . g e t A d r e s s e ( i n d e x )
43 }) ;
44 };
45 };
46
47 /* *
48 * E n r e g i s t r e l e s é v é nements de c l i c k s s u r l e s b o u t o n s ” A j o u t e r une a d r e s s e ”
et
49 * l e s b o u t o n s ” Supprimer ” ou m o d i f i e r de t o u t e s l e s a d r e s s e s de l a p e r so n ne s
é lectionn ée .
50 * C e t t e f o n c t i o n d o i t ê t r e i n v o q u é e en c a s de s é l e c t i o n d ’ une n o u v e l l e
p e r so nne
51 * ( r e c o n s t r u c t i o n deu code HTML du panneau d e s d é t a i l s ) .
52 */
53 var r e g i s t e r B u t t o n C l i c k E v e n t s = function ( ) {
54 var idBoutonSupprimerAdresse ,
55 idBoutonModifierAdresse ;
56 // E n r e g i s t r e m e n t du Handler du c l i c k pour a j o u t e r une a d r e s s e
57 $ ( ”#b o u t o n A j o u t e r A d r e s s e ” ) . on ( ” c l i c k ” , c l i c k B o u t o n S a i s i e A d r e s s e ) ;
58
59 f or ( var i =0 ; i < myApp . modele . s e l e c t e d P e r s o n n e . ge tNbAdr es se s ( ) ; ++i ) {
60 idBoutonSupprimerAdresse = ” boutonSupprimerAdresse_ ” +
61 myApp . modele . s e l e c t e d P e r s o n n e . g e t A d r e s s e ( i ) . g e t P r o p e r t y ( ’ i d ’ ) ;
62 $ ( ”#” + idBoutonSupprimerAdresse ) . on ( ” c l i c k ” ,
registerHelperSupprimerAdresse ( i ) ) ;
63 idBoutonModifierAdresse = ” boutonModifierAdresse_ ” +
64 myApp . modele . s e l e c t e d P e r s o n n e . g e t A d r e s s e ( i ) . g e t P r o p e r t y ( ’ i d ’ ) ;
65 $ ( ”#” + i d B o u t o n M o d i f i e r A d r e s s e ) . on ( ” c l i c k ” , r e g i s t e r H e l p e r M o d i f i e r A d r e s s e
(i));
66 }
67 }

91
Rémy Malgouyres, http://malgouyres.org Programmation Web Côté Client, JS et jQuery

68
69 // /////////////////////////////////////////////////////
70 // G e s t i o n n a i r e de s u b m i t f o r m u l a i r e d ’ a j o u t de a d r e s s e .
71
72 /* *
73 * G e s t i o n n a i r e de l ’ é v é nement s u b m i t du f o r m u l a i r e .
74 * @param { Event } jQuery e v e n t c o r r e s p o n d a n t au h a n d l e r .
75 */
76 var fo r m H a nd l e r A j o ut A d r e s s e = function ( e v e n t ) {
77
78 // É v i t e r d ’ a p p e l e r l ’ ” a c t i o n ” par d é f a u t ( ) s c r i p t PHP, e t c . . . )
79 // du f o r m u l a i r e l o r s du s u b m i t
80 event . preventDefault ( ) ;
81
82 // p u b l i c a t i o n a u p r è s du mé d i a t o r
83 myApp . g u i . m e d ia t o r . p u b l i s h ( ” a d r e s s e / c r e a t e ” , {
84 p e r s o n n e : myApp . modele . s e l e c t e d P e r s o n n e
85 }) ;
86 } // f i n du g e s t i o n n a i r e formHandlerAjout ( )
87
88 // E n r e g i s t r e m e n t du Handler du s u b m i t du f o r m u l a i r e v i a jQuery
89 $ ( ”#a j o u te r A d r e sse Fo r m ” ) . on ( ” s u b m i t ” , f o r m H a nd l e r Aj o u tA d r e s s e ) ;
90
91 // /////////////////////////////////////////////////////
92 // G e s t i o n n a i r e de s u b m i t f o r m u l a i r e d ’ a j o u t de a d r e s s e .
93
94 /* *
95 * G e s t i o n n a i r e de l ’ é v é nement s u b m i t du f o r m u l a i r e .
96 * @param { Event } jQuery e v e n t c o r r e s p o n d a n t au h a n d l e r .
97 */
98 var f o r m H a n d l e r M o d i f i e r A d r e s s e = function ( e v e n t ) {
99
100 // É v i t e r d ’ a p p e l e r l ’ ” a c t i o n ” par d é f a u t ( ) s c r i p t PHP, e t c . . . )
101 // du f o r m u l a i r e l o r s du s u b m i t
102 event . preventDefault ( ) ;
103
104 // p u b l i c a t i o n a u p r è s du mé d i a t o r
105 myApp . g u i . m e d ia t o r . p u b l i s h ( ” a d r e s s e / u p d a t e ” , {
106 p e r s o n n e : myApp . modele . s e l e c t e d P e r s o n n e
107 }) ;
108 } // f i n du g e s t i o n n a i r e formHandlerAjout ( )
109
110 // E n r e g i s t r e m e n t du Handler du s u b m i t du f o r m u l a i r e v i a jQuery
111 $ ( ”#modifierAdresseForm ” ) . on ( ” s u b m i t ” , f o r m H a n d l e r M o d i f i e r A d r e s s e ) ;
112
113 // E n r e g i s t r e r l e s c l i c k s l o r s de l ’ i n i t i a l i s a t i o n
114 registerButtonClickEvents () ;
115
116 // Permet à l a mé t h o d e q u i r e g é nè re l e panneau d e s d é t a i l s de r e c r é er ,
117 // v i a l e mé d i a t o r , l e s é v é nements ” c l i c k ” s u r l e s b o u t o n s dans l e panneau d e s
dé t a i l s .
118 myApp . g u i . m e d i a t o r . s u b s c r i b e ( ” p e r so n ne / d e t a i l s R e b u i l t ” ,
registerButtonClickEvents ) ;
119 }]) ;

92
Chapitre 5 : Exemple d’Application Interactive

5.5.2 Boutons d’ajout, de suppression, et de modification


Le bouton d’ajout d’une adresse, qui existe un un seul exemplaire car il dépend uniquement de
la personne, est le plus simple. Il faut créer un formulaire vierge pour la saisie d’une adresse.
Comme pour une personne, on utilise la possibilité de passer null comme argument de la
fabrique d’adresse, qui crée alors une adresse par défaut, sans créer d’erreurs pour les champs
vides (même pour les champs obligatoires).
exemples/ihm/ex12_guiBoutonAjouterAdresse.js
1 /* *
2 * Dé f i n i t i o n e t e n r e g i s t r e m e n t d e s c a l l b a c k s a p p e l é s à g é r e r l e c l i c s u r l e
bouton
3 * ” m o d i f i e r ” l a pe r so nn e s é l e c t i o n n é e .
4 */
5 myApp . addModule . apply (myApp . gui , [ ” c a l l b a c k s C l i c k A j o u t e r ” , function ( ) {
6
7 /* *
8 * Géné r a t i o n du code HTML du f o r m u l a i r e de m o d i f i c a t i o n de l a p e r so nne s é
lectionn ée .
9 */
10 var getHtmlFormInputs = function ( ) {
11 return ”<span s t y l e =\”width :360 px ; display : i n l i n e −b l o c k ; vertical −align :
top ; \ ”>” +
12 ”<p s t y l e =\”width : 360 px ; display : i n l i n e −b l o c k ; text −align :c e n t e r ;
padding : 15 px ; \ ”>” +
13 ”<tr ong>S a i s i e d ’ une n o u v e l l e a d r e s s e</s trong>” +
14 ”<br />pour ” + myApp . modele . s e l e c t e d P e r s o n n e . g e t P r o p e r t y ( ”nom” ) + ”<
/p>” +
15 myApp . g u i . getHtmlFormInputs (myApp . m e t i e r . a d r e s s e . c r e a t e I n s t a n c e ( null
) , ” a j o u te r A d r e sse Fo r m ” ) +
16 ”<l a b e l></ l a b e l><i nput t y p e =\” s u b m i t \” v a l u e =\” V a l i d e r \”></ i nput>” +
17 ”</span>” ;
18 }
19
20 /* *
21 * C a l l b a c k d ’ A f f i c h a g e ( v i a l e DOM) du f o r m u l a i r e dans l ’ é l é ment d ’ ID ”
mainForm”
22 * @param { O b j e c t } c o n t e x t A r g non u t i l i s é .
23 */
24 var r e p a i n t F o r m I n p u t s = function ( c o n te x t Ar g ) {
25 $ ( ”#modifierPersonneForm ” ) . empty ( ) ; // Vider l e s i n p u t s e t l e s é v é nements JS
existant
26 $ ( ”#ajouterPersonneForm ” ) . empty ( ) ; // Vider l e s i n p u t s e t l e s é v é nements JS
existant
27 $ ( ”#aj o u t e r A d r e sse Fo r m ” ) . empty ( ) ; // Vider l e s i n p u t s e t l e s é v é nements JS
existant
28 $ ( ”#modifierAdresseForm ” ) . empty ( ) ; // Vider l e s i n p u t s e t l e s é v é nements JS
existant
29
30 $ ( ”#aj o u t e r A d r e sse Fo r m ” ) . append ( getHtmlFormInputs ( ) ) ; // a j o u t e r l e s
nouveaux i n p u t s
31 };
32
33 // E n r e g i s t r e m e n t du c a l l b a c k
34 myApp . g u i . m e d i a t o r . s u b s c r i b e ( ” a d r e s s e / s a i s i e ” , r e p a i n t F o r m I n p u t s ) ;
35

93
Rémy Malgouyres, http://malgouyres.org Programmation Web Côté Client, JS et jQuery

36 }() ] ) ;

Les boutons de modification et de suppression des adresse doivent exister en autant d’exem-
plaire qu’il y a d’adresse. On crée donc un helper chargé de créer le callback correspondant à
chaque adresse.
exemples/ihm/ex13_guiBoutonModifierAdresse.js
1 /* *
2 * Dé f i n i t i o n e t e n r e g i s t r e m e n t d e s c a l l b a c k s a p p e l é s à g é r e r l e c l i c s u r l e
bouton
3 * ” m o d i f i e r ” l a pe r so nn e s é l e c t i o n n é e .
4 */
5 myApp . addModule . apply (myApp . gui , [ ” c a l l b a c k s C l i c k M o d i f i e r P e r s o n n e ” , function ( ) {
6
7 /* *
8 * Géné r a t i o n du code HTML du f o r m u l a i r e de m o d i f i c a t i o n de l a p e r so nne s é
lectionn ée .
9 */
10 var getHtmlFormInputs = function ( a d r e s s e ) {
11 return ”<span s t y l e =\”width :360 px ; display : i n l i n e −b l o c k ; vertical −align :
top ; \ ”>” +
12 myApp . g u i . getHtmlFormInputs ( a d r e s s e , ” modifierAdresseForm ” ) +
13 ”<l a b e l></ l a b e l><i nput t y p e =\” s u b m i t \” v a l u e =\” V a l i d e r \”></ i nput>” +
14 ”</span>” ;
15 }
16
17 /* *
18 * C a l l b a c k d ’ A f f i c h a g e ( v i a l e DOM) du f o r m u l a i r e dans l ’ é l é ment d ’ ID ”
modifierPersonneForm ”
19 * @param { O b j e c t } c o n t e x t A r g non u t i l i s é .
20 */
21 var r e p a i n t F o r m I n p u t s = function ( c o n te x t Ar g ) {
22 $ ( ”#modifierPersonneForm ” ) . empty ( ) ; // Vider l e s i n p u t s e t l e s é v é nements JS
existant
23 $ ( ”#ajouterPersonneForm ” ) . empty ( ) ; // Vider l e s i n p u t s e t l e s é v é nements JS
existant
24 $ ( ”#aj o u t e r A d r e sse Fo r m ” ) . empty ( ) ; // Vider l e s i n p u t s e t l e s é v é nements JS
existant
25 $ ( ”#modifierAdresseForm ” ) . empty ( ) ; // Vider l e s i n p u t s e t l e s é v é nements JS
existant
26
27
28 $ ( ”#modifierAdresseForm ” ) . append ( getHtmlFormInputs ( c o nt e x tA r g . a d r e s s e ) ) ; //
a j o u t e r l e s nouveaux i n p u t s
29 };
30
31 // E n r e g i s t r e m e n t du c a l l b a c k
32 myApp . g u i . m e d i a t o r . s u b s c r i b e ( ” a d r e s s e / e d i t ” , r e p a i n t F o r m I n p u t s ) ;
33
34 } ( ) ] ) ;

exemples/ihm/ex14_guiBoutonSupprimerAdresse.js
1 /* *
2 * Dé f i n i t i o n e t e n r e g i s t r e m e n t d e s c a l l b a c k s a p p e l é s à g é r e r l e c l i c s u r l e
bouton

94
Chapitre 5 : Exemple d’Application Interactive

3 * ” modifier ” la adresse s é lectionn ée .


4 */
5 myApp . addModule . apply (myApp . gui , [ ” c a l l b a c k s C l i c k S u p p r i m e r A d r e s s e ” , function ( ) {
6
7 /* *
8 * C a l l b a c k q u i supprime l a a d r e s s e p a s s é e dans l ’ o b j e t p a s s é en argument .
9 * @param { O b j e c t } c o n t e x t A r g argument i n d i q u a n t l a a d r e s s e à su p p r i m e r .
10 * @param { a d r e s s e } c o n t e x t A r g . a d r e s s e r é f é r e n c e de l ’ i n s t a n c e de a d r e s s e à
su p p r i m e r dans l e modèle .
11 */
12 var d e l e t e A d r e s s e = function ( c o n te x t Ar g ) {
13
14 // S u p p r e s s i o n de l ’ a d r e s s e dans l a p e r so n ne
15 c o n t e x t Ar g . p e r s o n n e . d e l e t e A d r e s s e ( c on t e xt A r g . a d r e s s e ) ;
16
17 // Provoquer l a mise à j o u r de l a vue :
18 myApp . g u i . m e d i a t o r . p u b l i s h ( ” p e r so n ne / d e t a i l s C h a n g e d ” , {
19 a d r e s s e : myApp . modele . s e l e c t e d P e r s o n n e
20 }) ;
21 }
22
23 // E n r e g i s t r e m e n t du c a l l b a c k
24 myApp . g u i . m e d i a t o r . s u b s c r i b e ( ” a d r e s s e / d e l e t e ” , d e l e t e A d r e s s e ) ;
25
26 } ( ) ] ) ;

5.5.3 Création d’une nouvelle adresse


L’adresse est automatiquement ajoutée à la personne sélectionnée, et son ID est généré auto-
matiquement. Comme dans le cas d’une personne, les propriétés de l’adresse (autre que l’ID)
sont récupérées à partir des valeurs des inputs du formulaire.

exemples/ihm/ex15_guiAjouterAdresseFormValidate.js
1 /* *
2 * Dé f i n i t i o n e t e n r e g i s t r e m e n t du c a l l b a c k r é a g i s s s a n t à l a v a l i d a t i o n ( s u b m i t )
3 * du f o r m u l a i r e de m o d i f i c a t i o n d ’ une a d r e s s e .
4 */
5 myApp . addModule . apply (myApp . gui , [ ” c a l l b a c k s V a l i d a t e A j o u t e r A d r e s s e F o r m ” ,
function ( ) {
6
7
8 /* *
9 * M o d i f i e l e modèle à p a r t i r d e s donn é e s s a i s i e s dans l e f o r m u l a i r e
10 */
11 var updateModel = function ( ) {
12 // 1) Mise à j o u r d e s donn é e s du modèle
13 // à p a r t i r d e s v a l e u r s d e s i n p u t s du f o r m u l a i r e
14 var propertyName ,
15 inputId ;
16
17 // Ajout d ’ un a d r e s s e v i d e dans l a c o l l e c t i o n
18 var n o u v e l l e A d r e s s e = myApp . m e t i e r . a d r e s s e . c r e a t e I n s t a n c e ( null ) ;
19 myApp . modele . s e l e c t e d P e r s o n n e . addAdresse ( n o u v e l l e A d r e s s e ) ;
20

95
Rémy Malgouyres, http://malgouyres.org Programmation Web Côté Client, JS et jQuery

21 // Pour chaque p r o p r i é t é ( chaque i n p u t du f o r m u l a i r e )


22 f or ( var j =0 ; j< myApp . m e t i e r . a d r e s s e . g e t P r o p e r t y L i s t ( ) . l e n g t h ; ++j ) {
23 propertyName = myApp . m e t i e r . a d r e s s e . g e t P r o p e r t y L i s t ( ) [ j ] ;
24 i f ( propertyName != ” i d ” ) {
25 // c a l c u l de l ’ ID de l ’ i n p u t
26 i n p u t I d = myApp . g u i . g e t I n p u t I d ( {
27 propertyName : propertyName ,
28 formId : ” aj o u te r A d r e ss e Fo r m ”
29 }) ;
30 // M o d i f i c a t i o n de l a p r o p r i é t é de l a a d r e s s e
31 // a v e c l a v a l e u r s a i s i e dans l ’ i n p u t .
32 n o u v e l l e A d r e s s e . s e t P r o p e r t y ( propertyName ,
33 document . getElementById ( i n p u t I d ) . v a l u e
34 );
35 }
36 }
37
38 // Provoquer l a mise à j o u r de l a vue ( panneau d e s d é t a i l s )
39 myApp . g u i . m e d i a t o r . p u b l i s h ( ” p e r so n ne / d e t a i l s C h a n g e d ” , {
40 p e r s o n n e : myApp . modele . s e l e c t e d P e r s o n n e
41 }) ;
42 // Provoquer l a r e q u ê t e AJAX pour l ’ i m p l é m e nt a t i o n de l a p e r s i s t a n c e
43 myApp . g u i . m e d i a t o r . p u b l i s h ( ” a d r e s s e / c r e a t e d ” , {
44 p e r s o n n e : myApp . modele . s e l e c t e d P e r s o n n e ,
45 adresse : nouvelleAdresse
46 }) ;
47
48 };
49
50 // E n r e g i s t r e m e n t du c a l l b a c k de l ’ é v é nement de v a l i d a t i o n du f o r m u l a i r e
51 myApp . g u i . m e d i a t o r . s u b s c r i b e ( ” a d r e s s e / c r e a t e ” , updateModel ) ;
52
53 }() ] ) ;

5.5.4 Modification d’une adresse


La modification d’une adresse après modification présente la difficulté suivante : il faut retrouver
l’instance d’adresse à modifier, parmis les adresses de la personne sélectionnée. Nous avons
choisi de mettre un champs caché avec l’ID dans le formulaire (voir la partie 4.3.2). Il nous
faut alors rechercher l’ID de l’adresse dans les instances d’adresse de la personne sélectionnée.
Nous aurions aussi pu ajouter une référence vers l’adresse éditée dans le modèle.

exemples/ihm/ex16_guiModifierAdresseFormValidate.js
1 /* *
2 * Dé f i n i t i o n e t e n r e g i s t r e m e n t du c a l l b a c k r é a g i s s s a n t à l a v a l i d a t i o n ( s u b m i t )
3 * du f o r m u l a i r e de m o d i f i c a t i o n d ’ une p e r so nne .
4 */
5 myApp . addModule . apply (myApp . gui , [ ” c a l l b a c k s V a l i d a t e M o d i f i e r A d r e s s e F o r m ” ,
function ( ) {
6 // Fo r m u l a i r e de m o d i f i c a t i o n d ’ une p e r s o nn e
7
8 /* *
9 * M o d i f i e l e modèle à p a r t i r d e s donn é e s s a i s i e s dans l e f o r m u l a i r e
10 */

96
Chapitre 5 : Exemple d’Application Interactive

11 var updateModel = function ( ) {


12
13
14 // 1) Mise à j o u r d e s donn é e s du modèle
15 // à p a r t i r d e s v a l e u r s d e s i n p u t s du f o r m u l a i r e
16 var propertyName ,
17 inputId ;
18
19 // Recherche de l ’ a d r e s s e q u i a é t é m o d i f i é e à p a r t i r de son ID u n i q u e
20 // L ’ ID s e t r o u v e en champs cach é du f o r m u l a i r e .
21 var i n p u t I d _ i d = myApp . g u i . g e t I n p u t I d ( {
22 propertyName : ” i d ” ,
23 formId : ” modifierAdresseForm ”
24 }) ;
25
26 // ID u n i q u e de l ’ a d r e s s e
27 var i d A d r e s s e = document . getElementById ( i n p u t I d _ i d ) . v a l u e ;
28 var a d r e s s e E n Q u e s t i o n ;
29 f or ( var i = 0 ; i < myApp . modele . s e l e c t e d P e r s o n n e . getNbAdre ss es ( ) ; ++i ) {
30 i f ( i d A d r e s s e == myApp . modele . s e l e c t e d P e r s o n n e . g e t A d r e s s e ( i ) . g e t P r o p e r t y ( ’
id ’ ) ){
31 a d r e s s e E n Q u e s t i o n = myApp . modele . s e l e c t e d P e r s o n n e . g e t A d r e s s e ( i ) ;
32 }
33 }
34 i f ( a d r e s s e E n Q u e s t i o n === u n d e f i n e d ) {
35 throw new E r r o r ( ” Adresse i n t r o u v a b l e ( ID i n e x i s t a n t ) ” ) ;
36 }
37
38 // Pour chaque p r o p r i é t é ( chaque i n p u t du f o r m u l a i r e )
39 f or ( var j =0 ; j< myApp . m e t i e r . a d r e s s e . g e t P r o p e r t y L i s t ( ) . l e n g t h ; ++j ) {
40 propertyName = myApp . m e t i e r . a d r e s s e . g e t P r o p e r t y L i s t ( ) [ j ] ;
41 i f ( propertyName != ” i d ” ) {
42 // c a l c u l de l ’ ID de l ’ i n p u t
43 i n p u t I d = myApp . g u i . g e t I n p u t I d ( {
44 propertyName : propertyName ,
45 formId : ” modifierAdresseForm ”
46 }) ;
47 // M o d i f i c a t i o n de l a p r o p r i é t é de l a p e r s o nn e
48 // a v e c l a v a l e u r s a i s i e dans l ’ i n p u t .
49 a d r e s s e E n Q u e s t i o n . s e t P r o p e r t y ( propertyName ,
50 document . getElementById ( i n p u t I d ) . v a l u e
51 );
52
53 }
54 }
55 // Provoquer l a mise à j o u r d e s é l é ments de l a vue o b s e r v a n t l a pe r so nn e
56 myApp . g u i . m e d i a t o r . p u b l i s h ( ” p e r so n ne / d e t a i l s C h a n g e d ” , {
57 p e r s o n n e : null
58 }) ;
59
60 // Provoquer l a mise à j o u r d e s é l é ments de l a vue o b s e r v a n t l a pe r so nn e
61 myApp . g u i . m e d i a t o r . p u b l i s h ( ” a d r e s s e / changed ” , {
62 p e r s o n n e : myApp . modele . s e l e c t e d P e r s o n n e ,
63 adresse : adresseEnQuestion
64 }) ;
65 };

97
Rémy Malgouyres, http://malgouyres.org Programmation Web Côté Client, JS et jQuery

66
67 // E n r e g i s t r e m e n t du c a l l b a c k de l ’ é v é nement de v a l i d a t i o n du f o r m u l a i r e
68 myApp . g u i . m e d i a t o r . s u b s c r i b e ( ” a d r e s s e / u p d a t e ” , updateModel ) ;
69
70 }() ] ) ;

98
Chapitre 6

Requêtes Asynchrones et API Restful

6.1 Qu’est-ce qu’une requête asynchrone ?


Les requêtes asynchrones XMLHttpRequest permettent d’exécuter (suite à une événement côté
client) une requête HTTP (exécution d’un CGI, par exemple en PHP) sur le serveur. On parle
de requête asynchrone car le client n’est pas bloqué en attendant la réponse du serveur : le
déroulement du programme côté client peut se poursuivre, et la réponse du serveur est gérée
par des callbacks.
Malgré le nom XMLHttpRequest, les requêtes asynchrones permettent d’échanger avec le
serveur d’autres types de données que du XML. Nous utiliserons dans ce cours des données
JSON.
Le codage JSON perrmet de coder sous forme de chaîne de caractères des collections d’ob-
jets. Ainsi, on pourra, par exemple, coder en JSON une collection d’objets en PHP (tableau
associatif), puis transmettre la chaîne JSON via une requête asynchrone, et enfin reconstituer
une collection d’objets en JavaScript pour générer, par exemple, une mise en forme HTML
dans le document.
Voici un exemple de code JSON d’un tableau associatif (qui contient lui-même un tableau
de descriptions de formats) :
{
"id": 654,
"denomination": "Tutoriel JavaScript",
"prix unitaire": 0.50,
"formats": ["PDF","Postscript","HTML","ePub"]
}
On peut, par exemple, générer un tel tableau en PHP par le code suivant :

1 <?php
2 $myArray = a r r a y ( ” i d ” => 6 5 4 ,
3 ” denomination ” => ” T u t o r i e l J a v a S c r i p t ” ,
4 ” p r i x u n i t a i r e ” => 0 . 5 0 ,
5 ” f o r m a t s ” => a r r a y ( ”PDF” , ” P o s t s c r i p t ” , ”HTML” , ” ePub ” ) ) ;
6
7 echo json_encode ( $myArray ) ;
8 ?>

99
Rémy Malgouyres, http://malgouyres.org Programmation Web Côté Client, JS et jQuery

6.2 Requête Ajax


Le méthode ajax de jQuery perrmet d’effectuer une requête XMLHttpRequest qui transmet des
paramètres (un objet JavaScript) à un CGI (ici en PHP), via une URL. Dans notre exemple, le
serveur reçoit lui-même un objet (propriété data) côdé en JSON, et génère lui-même du code
JSON. Le programme client récupère du code JSON générée sur la sortie standard du CGI, et
reconstitue une objet JavaScript.
Voici notre exemple où le code JavaScript côté client récupère une collection d’objet créée
par le CGI et la met en forme en HTML. Trois boutons permettent de tester :
• Un cas sans erreur ;

• Un cas où la gestion d’erreur est implémentée en PHP côté serveur ;

• Un cas où la requête AJAX elle-même échoue.


Les trois callbacks suivants sont utilisés pour gérer la requête :
• success en cas de succès de la requête ;

• error en cas d’échec de la requête

• complete, ici utilisé pour mettre à jour la vue, que ce soit en cas de succès ou en cas
d’échec de la requête.
Je programme en JavaScript côté client est le suivant :

exemples/ajax/ex02_ajax.html
1 /<! d o c t y p e html>
2 <html lang=” f r ”>
3 <head>

100
Chapitre 6 : Requêtes Asynchrones et API Restful

4 <meta charset=” utf−8 ”>


5 <t i t l e>Requ ê t e Ajax</ t i t l e>
6 <s c r i p t src=” . / j q u e r y . j s ”></s c r i p t>
7 <l i nk rel=” s t y l e s h e e t ” href=” b a s i c S t y l e . c s s ” />
8 </head>
9
10 <body>
11 <h1>Opé r a t i o n <i>GET</ i> Codé avec JSON</h1>
12
13 <p><button o n c l i c k = ” l a n c e r R e q u e t e ( 1 ) ”>C l i q u e z i c i</button> pour l a n c e r l a requ ê
t e s a n s e r r e u r</p>
14 <p><button o n c l i c k = ” l a n c e r R e q u e t e ( 0 ) ”>C l i q u e z i c i</button> pour l a n c e r l a requ ê
t e avec une e r r e u r g é r é e par l e s e r v e u r</p>
15 <p><button o n c l i c k = ” l a n c e r R e q u e t e (−1) ”>C l i q u e z i c i</button> pour l a n c e r une requ
ê t e q u i é choue</p>
16
17 <p id=” o u t p u t P a r a g r a p h ”></p>
18 <s c r i p t>
19
20 var model = {
21 paragraphText : ” ” ,
22 error : null ,
23 g e t E r r o r M e s s a g e : function ( ) {
24 return t h i s . error !== null ? ”<br />” + t h i s . error : ” ” ;
25 }
26 };
27
28 /**
29 * f o n c t i o n c a l l b a c k ex é c u t é e en c a s de s u c c è s de l a r e q u ê t e AJAX.
30 * La mé t h o d e p a r c o u r t l e s donn é e s r e t o u r n é e s par l e s e r v e u r au fo r m at JSON,
31 * e t c o n c a t è n e l e t e x t e dans l e modèle .
32 * @param { O b j e c t } r e t r i e v e d D a t a : c o l l e c t i o n d e s donn é e s d é cod é e s à p a r t i r du
JSON .
33 * La donn é e p e u t ê t r e un message d ’ e r r e u r .
34 */
35 var a j a x C a l l b a c k S u c c e s s = function ( r e t r i e v e d D a t a ) {
36 model . e r r o r = n u l l ;
37 model . paragraphText = ” ” ;
38 // Parcours e t a f f i c h a g e d e s donn é e s de l ’ o b j e t
39 f or ( var key in r e t r i e v e d D a t a ) {
40 model . paragraphText += key + ” −−−− > ” + r e t r i e v e d D a t a [ key ] +’<br />’ ;
41 }
42 };
43
44 /**
45 * f o n c t i o n c a l l b a c k ex é c u t é e en c a s d ’ é c h e c de l a r e q u ê t e AJAX.
46 * Une e r r e u r e s t a j o u t é e dans l e modèle e t l e t e x t e du p a r a g r a p h e e s t mis à
vide .
47 */
48 var a j a x C a l l b a c k E r r o r = function ( ) {
49 model . paragraphText = ” ” ;
50 model . error = ” Erreur : é c h e c de l a r e q u ê t e AJAX” ;
51 };
52
53 /**
54 * f o n c t i o n c a l l b a c k ex é c u t é e l o r s q u e l a r e q u ê t e AJAX s e t e r m i n e .

101
Rémy Malgouyres, http://malgouyres.org Programmation Web Côté Client, JS et jQuery

55 * Ce c a l l b a c k e s t a p p e l é en c a s d ’ é c h e c ET en c a s de s u c c è s de l a r e q u ê t e
AJAX.
56 * I c i , l a mé t h o d e met à j o u r l a vue en a f f i c h a n t l e t e x t e e t une é v e n t u e l l e
erreur .
57 */
58 var a j a x C a l l b a c k C o m p l e t e = function ( ) {
59 $ ( ”#o u t p u t P a r a g r a p h ” ) . append (
60 ”<p>” +
61 model . paragraphText +
62 model . g e t E r r o r M e s s a g e ( ) +
63 ”</p>” ) ;
64 }
65
66 /**
67 * G e s t i o n n a i r e de c l i c k s u r l e s boutons , q u i d é c l e n c h e une r e q u ê t e AJAX.
68 * @param { i n t } s i m p l e T e s t V a l u e donn é e t r a n s m i s e au s e r v e u r v i a l a p r o p r i é t é
simpleTest
69 * s i s i m p l e T e s t V a l u e e s t né g a t i f , une URL du s e r v e u r i n e x i s t a n t e
est u t i l i s ée ,
70 * p r o v o q u a n t l ’ é c h e c de l a r e q u ê t e ( c ’ e s t j u s t e pour l ’ e x e m p l e
...) .
71 */
72 var l a n c e r R e q u e t e = function ( s i m p l e T e s t V a l u e ) {
73
74 var u r l S e r v e u r = ” h t t p :/ / p r o g j s / e x e m p l e s / a j a x / e x 0 1 _ e n c o d e _ j s o n . php ” ;
75
76 // Pour p r o v o q u e r une r e q u ê t e q u i é choue complètement
77 i f ( s i m p l e T e s t V a l u e <0 ) { // URL q u i n ’ e x i s t e pas
78 u r l S e r v e u r = ” h t t p :/ / p r o g j s / e x e m p l e s / a j a x / b i d o n . php ” ;
79 }
80
81 // Lancement d ’ u n e r e q u ê t e AJAX a v e c donn é e s (POST) cod é e en JSON
82 var j q x h r = $ . a j a x ( {
83 // Envoyer l e s donn é e s de l a p e r s o nn e a v e c l e f o r ma t JSON
84 dataType : ” j s o n ” ,
85 u r l : u r l S e r v e u r , // URL du s e r v e u r
86 method : ’ p o s t ’ , // Envoyer l e s donn é e s dans l e t a b l e a u $_POST
87 contentType : ’application/x−www−form−urlencoded’ ,
88 // donn é e s à t r a n s m e t t r e au s e r v e u r
89 data : {
90 simpleTest : simpleTestValue
91 },
92 // Mé t h o d e c a l l b a c k q u i r e c o n s t r u i t l e modèle en c a s de s u c c è s
93 success : ajaxCallbackSuccess ,
94 // Mé t h o d e c a l l b a c k q u i g è r e une é v é e n t u e l l e e r r e u r dans l a r e q u ê t e
95 error : a j a x C a l l b a c k E r r o r ,
96 // Mé t h o d e c a l l b a c k q u i met à j o u r s l a vue l a vue en c a s de s u c c è s ou
d’erreur
97 complete : ajaxCallbackComplete
98 }) ;
99 }
100
101 </s c r i p t>
102 </body>

Le programme en PHP côté serveur est le suivant :

102
Chapitre 6 : Requêtes Asynchrones et API Restful

workspace_progWeb_2a/ajax/ex01_encode_json.php
1 <?php
2 i f ( i s s e t ($_REQUEST[ ’ s i m p l e T e s t ’ ] ) && $_REQUEST[ ’ s i m p l e T e s t ’ ] == 1 ) {
3 $myArray = array ( ’ key1 ’ => 1 1 , ’ key2 ’ => 2 2 , ’ key3 ’ => 3 3 , ’ key4 ’ => 4 4 ) ;
4 } else {
5 $myArray = array ( ’ e r r o r ’ => ”<i>PHP</ i> Cannot r e t r i e v e d a t a ” ) ;
6 }
7
8 // Header HTTP
9 header ( ’ content−t y p e : a p p l i c a t i o n / j s o n ; c h a r s e t=u t f −8 ’ ) ;
10 echo json_encode ( $myArray ) ;
11 ?>

6.3 Qu’est-ce qu’une API REST (ou systèmes Restful) ?


L’arcitecture REST (representational state transfer) est, dans notre cadre, une architecture
d’application client-serveur, qui permet le lien entre une application côté client en Javascript
et un serveur web sur lequel s’exécutent des CGI.
Côté serveur, notre application permettra :

• Opération GET. De lire toutes les ressources (ici d’une table de base de données) ;

• Opération GET. De lire une ressource identifiée (ici une ligne d’une table de base de
données) de manière unique (par un identifiant unique) ;

• Opération POST. De créer une ressource (ici une ligne d’une table de base de données)
avec son identifiant unique ;

• Opération PUT. De modifier une ressource identifiée (ici une ligne d’une table de base
de données) de manière unique (par un identifiant unique) ;

• Opération DELETE. De détruire une ressource identifiée (ici une ligne d’une table de
base de données) de manière unique (par un identifiant unique) ;

En utilisant cette interface (service web), l’application côté client pourra accéder à la couche
persistance du serveur.
Des problèmes de sécurité peuvent se poser. Aussi, les opérations ne sont généralement pas
toutes acessibles à un même utilisateur. En général, l’opération GET ne permet pas de modifier
les données et est moins sensible en matière de sécurité. On aura éventuellement recours aux
mêmes techniques d’authentification des utilisateurs ou des programmes clients que dans la
sécurisation des sites webs côté serveur à base de CGI uniquement (exemple : gestion avancée
du numéro de session). L’exemple qui suit dans ce chapitre ne gère pas les problèmes
d’authentification et ne pourra donc pas être utilisé directement en production sans réflexion
sur les besoins de sécurité.

6.4 Exemple d’API Restful


Nous développons ici l’organisation d’une API Restful qui nous permettra d’implémenter la
persistance pour notre application Web en JavaScript présentée au chapitre 5.

103
Rémy Malgouyres, http://malgouyres.org Programmation Web Côté Client, JS et jQuery

L’implémentation de l’API s’appuie sur le cours de programmation Web côté serveur sur :
http://malgouyres.org/progweb

6.4.1 Le Front Controller


Le Front Controller nous permet d’identifier l’action, de déterminer si l’utilisateur a des droits
suffisants pour exécuter l’action, et d’appeler, en tenant compte du rôle de l’utilisateur et de
l’action, le contrôleur dédié qui va implémenter l’action. La gestion des erreurs (comme l’action
non définie) sera vue dans la partie 6.4.3.
exemples/clientServer/ex01_controleurFront.php
1 <?php
2 /* *
3 * @ b r i e f La c l a s s e C o n t r o l e u r i d e n t i f i e l ’ a c t i o n e t a p p e l l e l a mé t h o d e
4 * pour c o n s t r u i r e l e modèle c o r r e s p o n d a n t à l ’ a c t i o n .
5 * Le c o n t r o l e u r a p p e l l e a u s s i l a vue c o r r e s p o n d a n t e .
6 * I l g è r e a u s s i l e s e x c e p t i o n s e t a p p e l l e l e c a s é ch é ant une vue d ’ e r r e u r .
7 */
8 c l a s s ControleurFront {
9
10 /* *
11 * @ b r i e f C ’ e s t dans l e c o n t r u c t e u r que l e c o n t r ô l e u r f a i t son t r a v a i l .
12 */
13 f u n c t i o n __construct ( ) {
14 try {
15 // Ré cup é r a t i o n de l ’ a c t i o n
16 $ a c t i o n = i s s e t ($_REQUEST[ ’ a c t i o n ’ ] ) ? $_REQUEST[ ’ a c t i o n ’ ] : ” ” ;
17
18 // L ’ u t i l i s a t e u r e s t − i l i d e n t i f i é ? S i oui , q u e l e s t son r ô l e ?
19 $modele = A u t h e n t i c a t i o n : : r e s t o r e S e s s i o n ( ) ;
20 // $ r o l e = ( $modele−>g e t E r r o r ( ) === f a l s e ) ? $modele−>g e t R o l e ( ) : ” ” ;
21 // La g e s t i o n d e s r ô l e s au p r o c h a i n é p i s o d e . . .
22 $ r o l e = ” admin ” ;
23
24 // On d i s t i n g u e d e s c a s d ’ u t i l i s a t i o n , s u i v a n t l ’ a c t i o n
25 switch ( $ a c t i o n ) {
26
27 // 1) A c t i o n s c o n c e r n a n t l ’ a u t h e n t i f i c a t i o n :
28 case ” a u t h ” : // Vue de s a i s i e du l o g i n / password
29 case ” v a l i d a t e A u t h ” : // V a l i d a t i o n du l o g i n / password
30 $ a u t h C t r l = new ControleurAuth ( $ a c t i o n ) ;
31 break ;
32
33 // 2) A c t i o n s a c c e s s i b l e s uniquement aux a d m i n i s t r a t e u r s :
34
35 case ” a d r e s s e −u p d a t e ” : // Met à j o u r une Adresse dans l a BD
36 case ” a d r e s s e −c r e a t e ” : // C r a t i o n d ’ une n o u v e l l e Adresse dans l a BD
37 case ” a d r e s s e −d e l e t e ” : // S u p r e s s i o n d ’ une Adresse à p a r t i r de son ID
38 i f ( $ r o l e == ” admin ” ) {
39 $adminCtrl = new ControleurAdminAdresse ( $ a c t i o n ) ;
40 } else {
41 $modele = new Model ( array ( ’ a u t h ’ => ” P e r m i s s i o n non a c c o r d é e ” ) ) ;
42 require ( C o n f i g : :getJsonOutput ( ) [ ” e r r o r H a n d l e d ” ] ) ;
43 }
44 break ;

104
Chapitre 6 : Requêtes Asynchrones et API Restful

45
46 case ” personne−u p d a t e ” : // Met à j o u r une Adresse dans l a BD
47 case ” personne−c r e a t e ” : // C r a t i o n d ’ une n o u v e l l e Adresse dans l a BD
48 case ” personne−d e l e t e ” : // S u p r e s s i o n d ’ une Adresse à p a r t i r de son ID
49 if ( $ r o l e == ” admin ” ) {
50 $adminCtrl = new ControleurAdminPersonne ( $ a c t i o n ) ;
51 } else {
52 $modele = new Model ( array ( ’ a u t h e n t i c a t i o n ’ => ” P e r m i s s i o n Denied ” ) ) ;
53 require ( C o n f i g : :getJsonOutput ( ) [ ” e r r o r H a n d l e d ” ] ) ;
54 }
55 break ;
56
57 // 3) A c t i o n s a c c e s s i b l e s aux v i s i t e u r s e t aux a d m i n i s t r a t e u r s :
58
59 case ” a d r e s s e −g e t ” : // A f f i c h a g e d ’ une Adresse à p a r t i r de son ID
60 case ” a d r e s s e −g e t − a l l ” : // A f f i c h a g e de t o u t e s l e s Adresse ’ s
61 // I c i , l ’ i m p l é m e nt a t i o n ( donc l e c o n t r ô l e u r ) d é pend pas du r ô l e
62 $ p u b l i c C t r l = new C o n t r o l e u r V i s i t o r A d r e s s e ( $ a c t i o n ) ;
63 break ;
64 case ” personne−g e t − a l l ” : // A f f i c h a g e de t o u t e s l e s Personne ’ s
65 $ p u b l i c C t r l = new C o n t r o l e u r V i s i t o r P e r s o n n e ( $ a c t i o n ) ;
66 break ;
67 default :
68 $modele = new Model ( array ( ’ a c t i o n ’ => ” Action non d é f i n i e ( r e s s o u r c e ( s
) introuvables )”) ) ;
69 require ( C o n f i g : :getJsonOutput ( ) [ ” e r r o r H a n d l e d ” ] ) ;
70 }
71 } c a t c h ( E x c e p t i o n $e ) { // Page d ’ e r r e u r par d é f a u t
72 $modele = new Model ( array ( ’ e x c e p t i o n ’ => $e−>getMessage ( ) ) ) ;
73 require ( C o n f i g : :getJsonOutput ( ) [ ” e r r o r H a n d l e d ” ] ) ;
74 }
75 }
76 }
77 ?>

6.4.2 Récupération des données venant du client


Les données client sont issues d’une requête AJAX présentée dans les parties 6.5.2 et 6.5.2.
Dans le cas d’une personnes, on a envoyé une objet dans une propriété personne.
exemples/clientServer/ex02_validationPersonne.php
1 <?php
2 // Les p r o p r i é t é s de l a pe r so nne s o n t dans un t a b l e a u a s s o c i a t i f $_REQUEST[ ’
p e r s o nn e ’ ]
3 // ( v o i r l a p r o p r i é t é d a t a d e s p r o p r i é t é s de l a r e q u ê t e AJAX
4
5 $ i d=” ” ;
6 i f ( i s s e t ($_REQUEST[ ’ p e r so n ne ’ ] [ ’ i d ’ ] ) ) {
7 $ i d = f i l t e r _var ($_REQUEST[ ’ p e r so n ne ’ ] [ ’ i d ’ ] , FILTER_SANITIZE_STRING) ;
8 }
9
10 $nom=” ” ;
11 i f ( i s s e t ($_REQUEST[ ’ p e r so n ne ’ ] [ ’nom ’ ] ) ) {
12 $nom = f i l t e r _var ($_REQUEST[ ’ p e r s o nn e ’ ] [ ’nom ’ ] , FILTER_SANITIZE_STRING) ;
13 }

105
Rémy Malgouyres, http://malgouyres.org Programmation Web Côté Client, JS et jQuery

14 ?>

Dans le cas d’une personnes, on a envoyé une objet dans une propriété personne, qui est de
type tableau associatif.

exemples/clientServer/ex02_zValidationAdresse.php
1 <?php
2 // Les p r o p r i é t é s de l a pe r so nne s o n t dans un t a b l e a u a s s o c i a t i f $_REQUEST[ ’
adresse ’]
3 // ( v o i r l a p r o p r i é t é d a t a d e s p r o p r i é t é s de l a r e q u ê t e AJAX
4
5 $ i d=” ” ;
6 i f ( i s s e t ($_REQUEST[ ’ a d r e s s e ’ ] [ ’ i d ’ ] ) ) {
7 $ i d = f i l t e r _var ($_REQUEST[ ’ a d r e s s e ’ ] [ ’ i d ’ ] , FILTER_SANITIZE_STRING) ;
8 }
9 $ i d P e r s o n n e=” ” ;
10 i f ( i s s e t ($_REQUEST[ ’ a d r e s s e ’ ] [ ’ i d P e r s o n n e ’ ] ) ) {
11 $ i d P e r s o n n e = f i l t e r _var ($_REQUEST[ ’ a d r e s s e ’ ] [ ’ i d P e r s o n n e ’ ] ,
FILTER_SANITIZE_STRING) ;
12 }
13 $numeroRue=” ” ;
14 i f ( i s s e t ($_REQUEST[ ’ a d r e s s e ’ ] [ ’ numeroRue ’ ] ) ) {
15 $numeroRue = f i l t e r _var ($_REQUEST[ ’ a d r e s s e ’ ] [ ’ numeroRue ’ ] ,
FILTER_SANITIZE_STRING) ;
16 }
17 $ r u e=” ” ;
18 i f ( i s s e t ($_REQUEST[ ’ a d r e s s e ’ ] [ ’ rue ’ ] ) ) {
19 $ r u e = f i l t e r _var ($_REQUEST[ ’ a d r e s s e ’ ] [ ’ rue ’ ] , FILTER_SANITIZE_STRING) ;
20 }
21 $complementAdresse=” ” ;
22 i f ( i s s e t ($_REQUEST[ ’ a d r e s s e ’ ] [ ’ complementAdresse ’ ] ) ) {
23 $complementAdresse = f i l t e r _var ($_REQUEST[ ’ a d r e s s e ’ ] [ ’ complementAdresse ’ ] ,
FILTER_SANITIZE_STRING) ;
24 }
25 $ c o d e P o s t a l=” ” ;
26 i f ( i s s e t ($_REQUEST[ ’ a d r e s s e ’ ] [ ’ c o d e P o s t a l ’ ] ) ) {
27 $ c o d e P o s t a l = f i l t e r _var ($_REQUEST[ ’ a d r e s s e ’ ] [ ’ c o d e P o s t a l ’ ] ,
FILTER_SANITIZE_STRING) ;
28 }
29 $ v i l l e=” ” ;
30 i f ( i s s e t ($_REQUEST[ ’ a d r e s s e ’ ] [ ’ v i l l e ’ ] ) ) {
31 $ v i l l e = f i l t e r _var ($_REQUEST[ ’ a d r e s s e ’ ] [ ’ v i l l e ’ ] , FILTER_SANITIZE_STRING) ;
32 }
33 $pays=” France ” ;
34 i f ( i s s e t ($_REQUEST[ ’ a d r e s s e ’ ] [ ’ pays ’ ] ) && $_REQUEST[ ’ a d r e s s e ’ ] [ ’ pays ’ ] != ” ” )
{
35 $pays = f i l t e r _var ($_REQUEST[ ’ a d r e s s e ’ ] [ ’ pays ’ ] , FILTER_SANITIZE_STRING) ;
36 }
37 ?>

6.4.3 Génération des données JSON représentant le modèle


La classe Config définit les URL des fichiers de génération de JSON, pour éviter les URL en
dûr, comme pour les vues d’un CGI.

106
Chapitre 6 : Requêtes Asynchrones et API Restful

exemples/clientServer/ex03_config.php
1 <?php
2 /* *
3 * @ b r i e f C l a s s e de c o n f i g u r a t i o n
4 * Donne a c c è s aux paramères sp é c i f i q u e s c o n c e r n a n t l ’ a p p l i c a t i o n
5 * t e l l e s que l e s chemins v e r s l e s vues , l e s v u e s d ’ e r r e u r ,
6 * l e s hash pour l e s ID de s e s s i o n s , e t c .
7 */
8 c l a s s Config
9 {
10 /* *
11 * @ b r i e f r e t o u r n e l e t a b l e a u d e s ( chemins v e r s l e s ) f i c h i e r s de g éné r a t i o n
de JSON
12 */
13 p u b l i c s t a t i c f u n c t i o n getJsonOutput ( ) {
14 // Racine du s i t e
15 global $rootDirectory ;
16 // Ré p e r t o i r e c o n t e n a n t l e s f i c h i e r s de g éné r a t i o n de JSON
17 $ j s o n D i r e c t o r y = $ r o o t D i r e c t o r y . ” json /” ;
18 r e t u r n array (
19 ” c o l l e c t i o n P e r s o n n e ” => $ j s o n D i r e c t o r y . ” j s o n C o l l e c t i o n P e r s o n n e
. php ” ,
20 ” i n s t a n c e P e r s o n n e ” => $ j s o n D i r e c t o r y . ” j s o n I n s t a n c e P e r s o n n e . php
”,
21 ” s u c c e s s ” => $ j s o n D i r e c t o r y . ” j s o n S u c c e s s . php ” ,
22 ” e r r o r H a n d l e d ” => $ j s o n D i r e c t o r y . ” j s o n E r r o r H a n d l e d . php ” ,
23 );
24 }
25
26 }
27 ?>

Pour chaque classe métier, un utilitaire permet de convertir les instances, ou les collections
d’instances, en tableaux associatifs.
exemples/clientServer/ex05_jsonAdresseJsonUtils.php
1 <?php
2 /* *
3 @ b r i e f Impl é mente l a c o n v e r s i o n d ’ i n s t a n c e s d ’ Adresse e t de c o l l e c t i o n s d ’
adresses
4 * v e r s d e s donn é e s s o u s l a forme de t a b l e a u x a s s o c i a t i f s dans l e b u t de g éné
r e r un
5 * codage JSON de c e s donn é e s ( par exemple a v e c l a f o n c t i o n json_encode ( ) )
6 */
7 class AdresseJsonUtils {
8
9 /* *
10 * @ b r i e f r e t o u r n e une r e p r é s e n t a t i o n d e s a t t r i b u t s d ’ une i n s t a n c e s o u s forme
de t a b l e a u a s s o c i a t i f .
11 * @param a d r e s s e un i n s t a n c e d ’ Adresse à c o n v e r t i r
12 * @return l a r e p r é s e n t a t i o n d e s donn é e s s o u s forme d ’ a r r a y .
13 */
14 publi c s t a t i c f u n c t i o n instanceToArray ( $adresse ) {
15 $arrayData = array (
16 ” i d ” => $ a d r e s s e −>g e t I d ( ) ,
17 ”numeroRue” => $ a d r e s s e −>getNumeroRue ( ) ,

107
Rémy Malgouyres, http://malgouyres.org Programmation Web Côté Client, JS et jQuery

18 ” rue ” => $ a d r e s s e −>getRue ( ) ,


19 ” complementAdresse ” => $ a d r e s s e −>getComplementAdresse ( ) ,
20 ” c o d e P o s t a l ” => $ a d r e s s e −>g e t C o d e P o s t a l ( ) ,
21 ” v i l l e ” => $ a d r e s s e −>g e t V i l l e ( ) ,
22 ” pays ” => $ a d r e s s e −>getPays ( )
23 );
24
25 r e t u r n $arrayData ;
26 }
27
28 /* *
29 * @ b r i e f r e t o u r n e une r e p r é s e n t a t i o n d e s a t t r i b u t s d e s i n s t a n c e s s o u s forme
de t a b l e a u a s s o c i a t i f .
30 * @param c o l l e c t i o n A d r e s s e un c o l l e c t i o n d ’ Adresse ( s ) à c o n v e r t i r
31 * @return l a r e p r é s e n t a t i o n d e s donn é e s s o u s forme d ’ a r r a y .
32 */
33 public s t a t i c function collectionToArray ( $collectionAdresses ){
34 $arrayData = array ( ) ;
35 foreach ( $ c o l l e c t i o n A d r e s s e s a s $ a d r e s s e ) {
36 // Ajout d ’ un é l é ment au t a b l e a u
37 $arrayData [ ] = s e l f : :i n s t a n c e T o A r r a y ( $ a d r e s s e ) ;
38 }
39
40 r e t u r n $arrayData ;
41 }
42 } // end o f c l a s s AdresseView
43 ?>

exemples/clientServer/ex04_jsonPersonneJsonUtils.php
1 <?php
2 /* *
3 @ b r i e f Impl é mente l a c o n v e r s i o n d ’ i n s t a n c e s de Personne e t de c o l l e c t i o n s d ’
adresses
4 * v e r s d e s donn é e s s o u s l a forme de t a b l e a u x a s s o c i a t i f s dans l e b u t de g éné
r e r un
5 * codage JSON de c e s donn é e s ( par exemple a v e c l a f o n c t i o n json_encode ( ) )
6 */
7 c l a s s PersonneJsonUtils {
8
9 /* *
10 * @ b r i e f r e t o u r n e une r e p r é s e n t a t i o n d e s a t t r i b u t s d ’ une i n s t a n c e s o u s forme
de t a b l e a u a s s o c i a t i f .
11 * @param a d r e s s e un i n s t a n c e de Personne à c o n v e r t i r
12 * @return l a r e p r é s e n t a t i o n d e s donn é e s s o u s forme d ’ a r r a y .
13 */
14 publi c s t a t i c f u n c t i o n instanceToArray ( $personne ) {
15 $arrayData = array (
16 ” i d ” => $personne −>g e t I d ( ) ,
17 ”nom” => $personne −>getNom ( ) ,
18 ” a d r e s s e s ” => A d r e s s e J s o n U t i l s : : c o l l e c t i o n T o A r r a y ( $personne −>g e t A d r e s s e s ( )
)
19 );
20
21 r e t u r n $arrayData ;
22 }

108
Chapitre 6 : Requêtes Asynchrones et API Restful

23
24 /* *
25 * @ b r i e f r e t o u r n e une r e p r é s e n t a t i o n d e s a t t r i b u t s d e s i n s t a n c e s s o u s forme
de t a b l e a u a s s o c i a t i f .
26 * @param c o l l e c t i o n A d r e s s e un c o l l e c t i o n de Personne ( s ) à c o n v e r t i r
27 * @return l a r e p r é s e n t a t i o n d e s donn é e s s o u s forme d ’ a r r a y .
28 */
29 public s t a t i c function collectionToArray ( $collectionPersonnes ){
30 $arrayData = array ( ) ;
31 foreach ( $ c o l l e c t i o n P e r s o n n e s a s $ p e r s o n n e ) {
32 // Ajout d ’ un é l é ment au t a b l e a u
33 $arrayData [ ] = s e l f : :i n s t a n c e T o A r r a y ( $ p e r s o n n e ) ;
34 }
35
36 r e t u r n $arrayData ;
37 }
38 }
39 ?>

exemples/clientServer/ex04_jsonPersonneJsonUtils.php
1 <?php
2 /* *
3 @ b r i e f Impl é mente l a c o n v e r s i o n d ’ i n s t a n c e s de Personne e t de c o l l e c t i o n s d ’
adresses
4 * v e r s d e s donn é e s s o u s l a forme de t a b l e a u x a s s o c i a t i f s dans l e b u t de g éné
r e r un
5 * codage JSON de c e s donn é e s ( par exemple a v e c l a f o n c t i o n json_encode ( ) )
6 */
7 c l a s s PersonneJsonUtils {
8
9 /* *
10 * @ b r i e f r e t o u r n e une r e p r é s e n t a t i o n d e s a t t r i b u t s d ’ une i n s t a n c e s o u s forme
de t a b l e a u a s s o c i a t i f .
11 * @param a d r e s s e un i n s t a n c e de Personne à c o n v e r t i r
12 * @return l a r e p r é s e n t a t i o n d e s donn é e s s o u s forme d ’ a r r a y .
13 */
14 publi c s t a t i c f u n c t i o n instanceToArray ( $personne ) {
15 $arrayData = array (
16 ” i d ” => $personne −>g e t I d ( ) ,
17 ”nom” => $personne −>getNom ( ) ,
18 ” a d r e s s e s ” => A d r e s s e J s o n U t i l s : : c o l l e c t i o n T o A r r a y ( $personne −>g e t A d r e s s e s ( )
)
19 );
20
21 r e t u r n $arrayData ;
22 }
23
24 /* *
25 * @ b r i e f r e t o u r n e une r e p r é s e n t a t i o n d e s a t t r i b u t s d e s i n s t a n c e s s o u s forme
de t a b l e a u a s s o c i a t i f .
26 * @param c o l l e c t i o n A d r e s s e un c o l l e c t i o n de Personne ( s ) à c o n v e r t i r
27 * @return l a r e p r é s e n t a t i o n d e s donn é e s s o u s forme d ’ a r r a y .
28 */
29 public s t a t i c function collectionToArray ( $collectionPersonnes ){
30 $arrayData = array ( ) ;

109
Rémy Malgouyres, http://malgouyres.org Programmation Web Côté Client, JS et jQuery

31 foreach ( $ c o l l e c t i o n P e r s o n n e s a s $ p e r s o n n e ) {
32 // Ajout d ’ un é l é ment au t a b l e a u
33 $arrayData [ ] = s e l f : :i n s t a n c e T o A r r a y ( $ p e r s o n n e ) ;
34 }
35
36 r e t u r n $arrayData ;
37 }
38 }
39 ?>

À la place des vues dans un CGI, un fichier génère les données JSON correspondant au
modèle (ici une collection de personnes).
exemples/clientServer/ex06_jsonCollectionPersonne.php
1 <?php
2 $arrayData = array ( ” e r r o r ” => n u l l , ” d a t a ” => P e r s o n n e J s o n U t i l s : :
c o l l e c t i o n T o A r r a y ( $modele−>getData ( ) ) ) ;
3
4 header ( ’ content−t y p e : a p p l i c a t i o n / j s o n ; c h a r s e t=u t f −8 ’ ) ;
5 echo json_encode ( $arrayData ) ;
6 ?>

Un fichier spécifique permet de renvoyer vers le client les messages correspondant aux
erreurs détectées par le serveur (erreurs d’accès au serveur de base de données, données de
forme incorrecte, etc.)
exemples/clientServer/ex06_jsonErrorHandled.php
1 <?php
2 // On r e t o u r n e l e t a b l e a u a s s o c i a t i f d e s e r r e u r s
3 header ( ’ content−t y p e : a p p l i c a t i o n / j s o n ; c h a r s e t=u t f −8 ’ ) ;
4 echo json_encode ( array ( ” e r r o r ” => $modele−>g e t E r r o r ( ) , ” d a t a ” => array ( ) ) ) ;
5 ?>

Un autre fichier permet, dans le cas où aucune donnée n’est attendue du client (comme par
exemple la suppression d’une personne) d’indiquer qu’aucune erreur n’a été détectée.
exemples/clientServer/ex06_jsonSuccess.php
1 <?php
2 // On r e t o u r n e une e r r e u r n u l l e t un o b j e t dada v i d e
3 header ( ’ content−t y p e : a p p l i c a t i o n / j s o n ; c h a r s e t=u t f −8 ’ ) ;
4 echo json_encode ( array ( ” e r r o r ” => n u l l , ” d a t a ” => array ( ) ) ) ;
5 ?>

6.4.4 Implémentation des actions des contrôleurs

exemples/clientServer/ex07_ControleurVisitorPersonne.php
1 <?php
2 /* *
3 * @ b r i e f La c l a s s e C o n t r o l e u r i d e n t i f i e l ’ a c t i o n e t a p p e l l e l a mé t h o d e
4 * pour c o n s t r u i r e l e modèle c o r r e s p o n d a n t à l ’ a c t i o n .
5 * Le c o n t r o l e u r a p p e l l e a u s s i l a vue c o r r e s p o n d a n t e .
6 * I l g è r e a u s s i l e s e x c e p t i o n s e t a p p e l l e l e c a s é ch é ant une vue d ’ e r r e u r .

110
Chapitre 6 : Requêtes Asynchrones et API Restful

7 */
8 class ControleurVisitorPersonne {
9
10 /* *
11 * @ b r i e f C ’ e s t dans l e c o n t r u c t e u r que l e c o n t r ô l e u r f a i t son t r a v a i l .
12 */
13 f u n c t i o n __construct ( $ a c t i o n ) {
14 // On d i s t i n g u e d e s c a s d ’ u t i l i s a t i o n , s u i v a n t l ’ a c t i o n
15 switch ( $ a c t i o n ) {
16 case ” personne−g e t ” : // A f f i c h a g e d ’ une Personne à p a r t i r de son ID
17 $ t h i s −>a c t i o n G e t ( ) ;
18 break ;
19 case ” personne−g e t − a l l ” : // A f f i c h a g e de t o u t e s l e s Personne ’ s
20 $ t h i s −>a c t i o n G e t A l l ( ) ;
21 break ;
22 default : // L ’ a c t i o n i n d é f i n i e ( page par d é f a u t , i c i ac cue i l )
23 require ( C o n f i g : :getVues ( ) [ ” d e f a u l t ” ] ) ;
24 break ;
25 }
26 }
27
28 /* *
29 * @ b r i e f Implemente l ’ a c t i o n ” g e t − a l l ” ( r é c u p è r e t o u t e s l e s i n s t a n c e s )
30 */
31 private function actionGetAll () {
32 $modele = M o d e l C o l l e c t i o n P e r s o n n e : :g e t M o d e l P e r s o n n e A l l ( ) ;
33 i f ( $modele−>g e t E r r o r ( ) === f a l s e ) {
34 require ( C o n f i g : :getJsonOutput ( ) [ ” c o l l e c t i o n P e r s o n n e ” ] ) ;
35 } else {
36 require ( C o n f i g : :getJsonOutput ( ) [ ” e r r o r H a n d l e d ” ] ) ;
37 }
38 }
39
40 /* *
41 * @ b r i e f Implemente l ’ a c t i o n ” g e t ” ( r é c u p è r e une i n s t a n c e à p a r t i r de ID )
42 */
43 private function actionGet () {
44 // ID de l ’ i n s t a n c e à r é cup é r e r
45 $rawId = i s s e t ($_REQUEST[ ’ i d ’ ] ) ? $_REQUEST[ ’ i d ’ ] : ” ” ;
46 $ i d = f i l t e r _var ( $rawId , FILTER_SANITIZE_STRING) ;
47 $modele = ModelPersonne : :getModelPersonne ( $ i d ) ;
48 i f ( $modele−>g e t E r r o r ( ) === f a l s e ) {
49 require ( C o n f i g : :getJsonOutput ( ) [ ” i n s t a n c e P e r s o n n e ” ] ) ;
50 } else {
51 require ( C o n f i g : :getJsonOutput ( ) [ ” e r r o r H a n d l e d ” ] ) ;
52 }
53 }
54 }
55 ?>

exemples/clientServer/ex08_ControleurAdminPersonne.php
1 <?php
2 /* *
3 * @ b r i e f La c l a s s e C o n t r o l e u r i d e n t i f i e l ’ a c t i o n e t a p p e l l e l a mé t h o d e
4 * pour c o n s t r u i r e l e modèle c o r r e s p o n d a n t à l ’ a c t i o n .

111
Rémy Malgouyres, http://malgouyres.org Programmation Web Côté Client, JS et jQuery

5 * Le c o n t r o l e u r a p p e l l e a u s s i l a vue c o r r e s p o n d a n t e .
6 * I l g è r e a u s s i l e s e x c e p t i o n s e t a p p e l l e l e c a s é ch é ant une vue d ’ e r r e u r .
7 */
8 c l a s s ControleurAdminPersonne {
9
10 /* *
11 * @ b r i e f C ’ e s t dans l e c o n t r u c t e u r que l e c o n t r ô l e u r f a i t son t r a v a i l .
12 */
13 f u n c t i o n __construct ( $ a c t i o n ) {
14 // On d i s t i n g u e d e s c a s d ’ u t i l i s a t i o n , s u i v a n t l ’ a c t i o n
15 switch ( $ a c t i o n ) {
16 case ” personne−u p d a t e ” : // Met à j o u r une Adresse dans l a BD
17 $ t h i s −>a c t i o n U p d a t e ( ) ;
18 break ;
19 case ” personne−c r e a t e ” : // C r a t i o n d ’ une n o u v e l l e Adresse dans l a BD
20 $ t h i s −>a c t i o n C r e a t e ( ) ;
21 break ;
22 case ” personne−d e l e t e ” : // S u p r e s s i o n d ’ une Adresse à p a r t i r de son ID
23 $ t h i s −>a c t i o n D e l e t e ( ) ;
24 break ;
25 default : // L ’ a c t i o n i n d é f i n i e ( page par d é f a u t , i c i ac cue i l )
26 $modele = new Model ( array ( ’ a c t i o n ’ => ” Action non d é f i n i e ( r e s s o u r c e ( s )
introuvables )”) ) ;
27 require ( C o n f i g : :getJsonOutput ( ) [ ” e r r o r H a n d l e d ” ] ) ;
28 break ;
29 }
30 }
31
32 /* *
33 * @ b r i e f Implemente l ’ a c t i o n ” u p d a t e ” ( met à j o u r une i n s t a n c e dans l a BD)
34 */
35 p r i v a t e f u n c t i o n actionUpdate ( ) {
36 // v a l i d e r ou n e t t o y e r l e s i n p u t s ( par exemple : f i l t e r _var )
37 require ( dirname (__FILE__) . ”/ v a l i d a t i o n P e r s o n n e . php ” ) ;
38 $modele = ModelPersonne : :getModelPersonneUpdate ( $id , $nom ) ;
39 i f ( $modele−>g e t E r r o r ( ) === f a l s e ) {
40 require ( C o n f i g : :getJsonOutput ( ) [ ” s u c c e s s ” ] ) ;
41 } else {
42 require ( C o n f i g : :getJsonOutput ( ) [ ” e r r o r H a n d l e d ” ] ) ;
43 }
44 }
45
46 /* *
47 * @ b r i e f Implemente l ’ a c t i o n ” c r e a t e ” ( c r é e une i n s t a n c e dans l a BD)
48 */
49 private function actionCreate () {
50 // v a l i d e r ou n e t t o y e r l e s i n p u t s ( par exemple : f i l t e r _var )
51 require ( dirname (__FILE__) . ”/ v a l i d a t i o n P e r s o n n e . php ” ) ;
52 $modele = ModelPersonne : :ge t M o de l P e r s o nn e Cr e a t e ( $id , $nom ) ;
53 i f ( $modele−>g e t E r r o r ( ) === f a l s e ) {
54 require ( C o n f i g : :getJsonOutput ( ) [ ” s u c c e s s ” ] ) ;
55 } else {
56 require ( C o n f i g : :getJsonOutput ( ) [ ” e r r o r H a n d l e d ” ] ) ;
57 }
58 }
59

112
Chapitre 6 : Requêtes Asynchrones et API Restful

60 /* *
61 * @ b r i e f Implemente l ’ a c t i o n ” d e l e t e ” ( supprime une i n s t a n c e à p a r t i r de son
ID )
62 */
63 private function actionDelete () {
64 // ID de l ’ i n s t a n c e à su p p r i m e r
65 $ i d = f i l t e r _var ($_REQUEST[ ’ i d ’ ] , FILTER_SANITIZE_STRING) ;
66 $modele = ModelPersonne : : d e l e t e P e r s o n n e ( $ i d ) ;
67 i f ( $modele−>g e t E r r o r ( ) === f a l s e ) {
68 require ( C o n f i g : :getJsonOutput ( ) [ ” s u c c e s s ” ] ) ;
69 } else {
70 require ( C o n f i g : :getJsonOutput ( ) [ ” e r r o r H a n d l e d ” ] ) ;
71 }
72 }
73
74 }
75 ?>

exemples/clientServer/ex09_ControleurAdminAdresse.php
1 <?php
2 /* *
3 * @ b r i e f La c l a s s e C o n t r o l e u r i d e n t i f i e l ’ a c t i o n e t a p p e l l e l a mé t h o d e
4 * pour c o n s t r u i r e l e modèle c o r r e s p o n d a n t à l ’ a c t i o n .
5 * Le c o n t r o l e u r a p p e l l e a u s s i l a vue c o r r e s p o n d a n t e .
6 * I l g è r e a u s s i l e s e x c e p t i o n s e t a p p e l l e l e c a s é ch é ant une vue d ’ e r r e u r .
7 */
8 c l a s s ControleurAdminAdresse {
9
10 /* *
11 * @ b r i e f C ’ e s t dans l e c o n t r u c t e u r que l e c o n t r ô l e u r f a i t son t r a v a i l .
12 */
13 f u n c t i o n __construct ( $ a c t i o n ) {
14 // On d i s t i n g u e d e s c a s d ’ u t i l i s a t i o n , s u i v a n t l ’ a c t i o n
15 switch ( $ a c t i o n ) {
16 case ” a d r e s s e −u p d a t e ” : // Met à j o u r une Adresse dans l a BD
17 $ t h i s −>a c t i o n U p d a t e ( ) ;
18 break ;
19 case ” a d r e s s e −c r e a t e ” : // C r a t i o n d ’ une n o u v e l l e Adresse dans l a BD
20 $ t h i s −>a c t i o n C r e a t e ( ) ;
21 break ;
22 case ” a d r e s s e −d e l e t e ” : // S u p r e s s i o n d ’ une Adresse à p a r t i r de son ID
23 $ t h i s −>a c t i o n D e l e t e ( ) ;
24 break ;
25 default : // L ’ a c t i o n i n d é f i n i e ( page par d é f a u t , i c i ac cue i l )
26 require ( C o n f i g : :getJsonOutput ( ) [ ” e r r o r H a n d l e d ” ] ) ;
27 break ;
28 }
29 }
30
31 /* *
32 * @ b r i e f Implemente l ’ a c t i o n ” u p d a t e ” ( met à j o u r une i n s t a n c e dans l a BD)
33 */
34 p r i v a t e f u n c t i o n actionUpdate ( ) {
35 // v a l i d e r ou n e t t o y e r l e s i n p u t s ( par exemple : f i l t e r _var )
36 require ( dirname (__FILE__) . ”/ v a l i d a t i o n A d r e s s e . php ” ) ;

113
Rémy Malgouyres, http://malgouyres.org Programmation Web Côté Client, JS et jQuery

37 $modele = ModelAdresse : :getModelAdresseUpdate ( $id , $i dP e r s onne , $numeroRue ,


$rue ,
38 $complementAdresse , $ c o d e P o s t a l , $ v i l l e , $pays ) ;
39 i f ( $modele−>g e t E r r o r ( ) === f a l s e ) {
40 require ( C o n f i g : :getJsonOutput ( ) [ ” s u c c e s s ” ] ) ;
41 } else {
42 require ( C o n f i g : :getJsonOutput ( ) [ ” e r r o r H a n d l e d ” ] ) ;
43 }
44 }
45
46 /* *
47 * @ b r i e f Implemente l ’ a c t i o n ” c r e a t e ” ( c r é e une i n s t a n c e dans l a BD)
48 */
49 private function actionCreate () {
50 // v a l i d e r ou n e t t o y e r l e s i n p u t s ( par exemple : f i l t e r _var )
51 require ( dirname (__FILE__) . ”/ v a l i d a t i o n A d r e s s e . php ” ) ;
52 $modele = ModelAdresse : :g e t M o d e l A d r e s s e C r e a t e ( $id , $idP e r s onne , $numeroRue ,
$rue ,
53 $complementAdresse , $ c o d e P o s t a l , $ v i l l e , $pays ) ;
54 i f ( $modele−>g e t E r r o r ( ) === f a l s e ) {
55 require ( C o n f i g : :getJsonOutput ( ) [ ” s u c c e s s ” ] ) ;
56 } else {
57 require ( C o n f i g : :getJsonOutput ( ) [ ” e r r o r H a n d l e d ” ] ) ;
58 }
59 }
60
61 /* *
62 * @ b r i e f Implemente l ’ a c t i o n ” d e l e t e ” ( supprime une i n s t a n c e à p a r t i r de son
ID )
63 */
64 private function actionDelete () {
65 // ID de l ’ i n s t a n c e à su p p r i m e r
66 $ i d = f i l t e r _var ($_REQUEST[ ’ i d ’ ] , FILTER_SANITIZE_STRING) ;
67 $modele = ModelAdresse : : d e l e t e A d r e s s e ( $ i d ) ;
68 i f ( $modele−>g e t E r r o r ( ) === f a l s e ) {
69 require ( C o n f i g : :getJsonOutput ( ) [ ” s u c c e s s ” ] ) ;
70 } else {
71 require ( C o n f i g : :getJsonOutput ( ) [ ” e r r o r H a n d l e d ” ] ) ;
72 }
73 }
74 }
75 ?>

6.5 Persistance avec AJAX


6.5.1 Construction du modèle à partir de la base de données

exemples/clientServer/ex10_persistanceRead.js
1 /* *
2 * Dé f i n i t i o n e t e n r e g i s t r e m e n t d e s c a l l b a c k s de chargement du modèle
3 * à p a r t i r d e s donn é e s s u r l e s e r v e u r par une r e q u ê t e AJAX.
4 * Permet l e chargement du modèle à p a r t i r de l a b a s e de donn é e s .
5 */

114
Chapitre 6 : Requêtes Asynchrones et API Restful

6 myApp . addModule . apply (myApp . gui , [ ” c a l l b a c k s R e b u i l d M o d e l F r o m S e r v e r ” , function ( ) {


7
8 /* *
9 * Informe l ’ u t i l i s a t e u r de l ’ e n s e m b l e d e s e r r e u r s d é t e c t é e s e t re nv oy é e s par
le serveur .
10 * @param { O b j e c t } d a t a E r r o r c o u p l e s c l e f / v a l e u r , où l a c l e f e s t une c a t é g o r i e
d ’ erreur
11 * ( ou un champs de f o r m u l a i r e ) , e t l a v a l e u r un message d ’
erreur .
12 */
13 var a l e r t E r r o r M e s s a g e s = function ( d a t a E r r o r ) {
14 var concatErrorMsg=” ” ;
15 i f ( d a t a E r r o r !== null ) {
16 for ( var key in d a t a E r r o r ) {
17 i f ( d a t a E r r o r . hasOwnProperty ( key ) ) {
18 concatErrorMsg += key + ” : ” + d a t a E r r o r [ key ] + ” \n” ;
19 }
20 }
21 a l e r t ( concatErrorMsg ) ;
22 }
23 };
24
25 /* *
26 * Mé t h o d e c a l l b a c k q u i e s t a p p e l é e en c a s de s u c c è s de l a r e q u ê t e AJAX.
27 * C e t t e mé t h o d e r e c o n s t r u i t l e modèle à p a r t i r d e s donn é e s du s e r v e u r .
28 * @param { O b j e c t } r e t r i e v e d D a t a donn é e s r e ¸ ues du s e r v e u r ( a p r è s p a r s i n g du
JSON)
29 * @param { O b j e c t | n u l l } r e t r i e v e d D a t a . e r r o r n u l l en l ’ a b s e n c e d ’ e r r e u r d é t e c t é
e par l e s e r v e u r ,
30 * ou un o b j e t dont l e s p r o p r i é t é s s o n t l e s messages d ’ e r r e u r r env o y é
e s par l e s e r v e u r .
31 * @param { O b j e c t } r e t r i e v e d D a t a . d a t a donn é e s re nv o y é e s par l e s e r v e u r :
32 * c o l l e c t i o n s d ’ o b j e t s p e r m e t t a n t de c o n s t r u i r e d e s per so nnes
, avec l e u r s a d r e s s e s .
33 */
34 var a j a x C a l l b a c k S u c c e s s = function ( r e t r i e v e d D a t a ) {
35 var a d r e s s e s D a t a , a d r e s s e I n s t a n c e ;
36
37 // S i aucune e r r e u r n ’ a é t é d é t e c t é e s u r l e s e r v e u r
38 i f ( r e t r i e v e d D a t a [ ” e r r o r ” ] === null && r e t r i e v e d D a t a [ ’ d a t a ’ ] !== u n d e f i n e d ) {
39 // Parcours d e s o b j e t s dans l e s donn é e s
40 for ( var key in r e t r i e v e d D a t a [ ’ d a t a ’ ] ) {
41 i f ( r e t r i e v e d D a t a [ ’ d a t a ’ ] . hasOwnProperty ( key ) ) {
42 // Cré a t i o n d ’ une p e r so n ne s a n s a d r e s s e
43 var newPersonne = myApp . m e t i e r . p e r s o n n e . c r e a t e I n s t a n c e ( {
44 i d : r e t r i e v e d D a t a [ ’ d a t a ’ ] [ key ] [ ” i d ” ] ,
45 nom : r e t r i e v e d D a t a [ ’ d a t a ’ ] [ key ] [ ”nom” ]
46 }) ;
47
48 // Parcours d e s o b j e t s d é f i n i s s a n t l e s a d r e s s e s
49 a d r e s s e s D a t a = r e t r i e v e d D a t a [ ’ d a t a ’ ] [ key ] [ ” a d r e s s e s ” ] ;
50 for ( var k e y A d r e s s e in a d r e s s e s D a t a ) {
51 i f ( a d r e s s e s D a t a . hasOwnProperty ( k e y A d r e s s e ) ) {
52 // Cré a t i o n e t a j o u t d ’ une a d r e s s e
53 a d r e s s e I n s t a n c e = myApp . m e t i e r . a d r e s s e . c r e a t e I n s t a n c e ( {
54 id : adressesData [ keyAdresse ] [ ” id ” ] ,

115
Rémy Malgouyres, http://malgouyres.org Programmation Web Côté Client, JS et jQuery

55 numeroRue : a d r e s s e s D a t a [ k e y A d r e s s e ] [ ”numeroRue” ] ,
56 r u e : a d r e s s e s D a t a [ k e y A d r e s s e ] [ ” rue ” ] ,
57 complementAdresse : a d r e s s e s D a t a [ k e y A d r e s s e ] [ ”
complementAdresse ” ] ,
58 codePostal : adressesData [ keyAdresse ] [ ” codePostal ” ] ,
59 v i l l e : adressesData [ keyAdresse ] [ ” v i l l e ” ] ,
60 pays : a d r e s s e s D a t a [ k e y A d r e s s e ] [ ” pays ” ]
61 }) ;
62 newPersonne . addAdresse ( a d r e s s e I n s t a n c e ) ;
63 }
64 }
65 myApp . modele . p e r s o n n e s . push ( newPersonne ) ; // a j o u t dans l e modèle
66 }
67 }
68 } else {
69 alertErrorMessages ( retrievedData [ ” error ” ] ) ;
70 }
71 };
72
73 /* *
74 * Mé t h o d e a p p e l é e l o r s q u e l a r e q u ê t e AJAX s e termine ,
75 * que ce s o i t a p r è s une e r r e u r ou a p r è s un s u c c è s .
76 * C e t t e mé t h o d e r e c o n s t r u i t l a vue ( a p r è s r e c o n s t r u c t i o n du modèle ) .
77 */
78 var a j a x C a l l b a c k C o m p l e t e = function ( r e t r i e v e d D a t a ) {
79
80 // Personne s é l e c t i o n n é e par d é f a u t
81 myApp . modele . s e l e c t e d P e r s o n n e = myApp . modele . p e r s o n n e s [ 0 ] ;
82
83 // La vue e s t r é i n i t i a l i s é e : on v i d e l e s é l é ments e t é v é nements
84 $ ( ”#l i s t e P e r s o n n e s ” ) . empty ( ) ;
85 $ ( ”#v u e D e t a i l ” ) . empty ( ) ;
86 $ ( ”#ajouterPersonneForm ” ) . empty ( ) ;
87 $ ( ”#modifierPersonneForm ” ) . empty ( ) ;
88 $ ( ”#aj o u t e r A d r e sse Fo r m ” ) . empty ( ) ;
89 $ ( ”#modifierAdresseForm ” ) . empty ( ) ;
90
91 // Provoquer l e pr e m i e r a f f i c h a g e de l a vue :
92 myApp . g u i . m e d i a t o r . p u b l i s h ( ” p e r so n ne / changed ” , {
93 p e r s o n n e : myApp . modele . s e l e c t e d P e r s o n n e
94 }) ;
95
96 // E n r e g i s t r e m e n t d e s é v é nements u t i l i s a t e u r s g é r é s par jQuery
97 myApp . g u i . i n i t J Q u e r y E v e n t s P e r s o n n e ( ) ;
98 myApp . g u i . i n i t J Q u e r y E v e n t s A d r e s s e ( ) ;
99 };
100
101 /* *
102 * Mé t h o d e a p p e l é e en c a s d ’ e r r e u r de l a r e q u ê t e AJAX e l l e même .
103 */
104 var a j a x C a l l b a c k E r r o r = function ( r e t r i e v e d D a t a ) {
105 a l e r t ( ” Erreur : é c h e c de l a r e q u ê t e a j a x ” ) ;
106 }
107
108 /* *
109 * C a l l b a c k a p p e l é l o r s de l ’ é v é nement ” p e r s o nn e / rea d ” du mé d i a t o r .

116
Chapitre 6 : Requêtes Asynchrones et API Restful

110 * E f f e c t u e une r e q u ê t e AJAX pour r é cup é r e r t o u t e s l e s p e r s o n n e s


111 * pour r e c o n s t r u i r e l e modèle de donn é e s .
112 */
113 var r e a d A l l P e r s o n n e = function ( ) {
114 // r e q u ê t e AJAX g e t cod é en JSON
115 var j q x h r = $ . a j a x ( {
116 // Envoyer l e s donn é e s de l a p e r so nne a v e c l e fo r m a t JSON
117 dataType : ” j s o n ” ,
118 u r l : ” h t t p :// p r o g j s / e x e m p l e s / c l i e n t S e r v e r / a p i /” , // URL du s e r v e u r
119 method : ’ p o s t ’ , // Envoyer l e s donn é e s dans l e t a b l e a u $_POST
120 contentType : ’ a p p l i c a t i o n /x−www−form−u r l e n c o d e d ’ ,
121 // donn é e s à t r a n s m e t t r e au s e r v e u r
122 data : {
123 a c t i o n : ” personne−g e t − a l l ”
124 },
125 // Mé t h o d e c a l l b a c k q u i r e c o n s t r u i t l e modèle en c a s de s u c c è s
126 success : ajaxCallbackSuccess ,
127 // Mé t h o d e c a l l b a c k q u i g è r e une é v é e n t u e l l e e r r e u r dans l a r e q u ê t e
128 error : ajaxCallbackError ,
129 // Mé t h o d e c a l l b a c k q u i met à j o u r s l a vue l a vue en c a s de s u c c è s ou d ’
erreur
130 complete : ajaxCallbackComplete
131 }) ;
132
133 };
134
135 // E n r e g i s t r e m e n t du c a l l b a c k de l ’ é v é nement de r e c o n s t r u c t i o n du modèle
136 myApp . g u i . m e d i a t o r . s u b s c r i b e ( ” p e r so n ne / read ” , r e a d A l l P e r s o n n e ) ;
137
138 }() ] ) ;

exemples/clientServer/ex10_index.html
1 <! doctype HTML>
2 <html l a n g=” f r ”>
3 <head>
4 <meta c h a r s e t=”UTF−8” />
5 <t i t l e>A p p l i c a t i o n i n t e r a c t i v e</ t i t l e>
6 <l i nk r e l=” s t y l e s h e e t ” h r e f=” b a s i c S t y l e . c s s ” />
7 </head>
8 <body>
9 <s c r i p t s r c=” . / m o d u l e s M e t i e r P r o t o t y p e . j s ”></s c r i p t>
10 <s c r i p t s r c=” . / modulesIHM . j s ”></s c r i p t>
11 <s c r i p t s r c=” . / p e r s i s t a n c e R e a d . j s ”></s c r i p t>
12 <s c r i p t s r c=” . / p e r s i s t a n c e C r e a t e P e r s o n n e . j s ”></s c r i p t>
13 <s c r i p t s r c=” . / p e r s i s t a n c e D e l e t e P e r s o n n e . j s ”></s c r i p t>
14 <s c r i p t s r c=” . / p e r s i s t a n c e U p d a t e P e r s o n n e . j s ”></s c r i p t>
15 <s c r i p t s r c=” . / p e r s i s t a n c e C r e a t e A d r e s s e . j s ”></s c r i p t>
16 <s c r i p t s r c=” . / p e r s i s t a n c e U p d a t e A d r e s s e . j s ”></s c r i p t>
17 <s c r i p t s r c=” . / p e r s i s t a n c e D e l e t e A d r e s s e . j s ”></s c r i p t>
18 <!−− Code HTML de l a vue −− S t r u c t u r e g é né r a l e de l a page HTML −−>
19
20 <button i d=” b o u t o n A j o u t e r P e r s o n n e ”>A j o u t e r une p e r s o n n e</button><br />
21 <span i d=” l i s t e P e r s o n n e s ” c l a s s=” p a n e l ”></span>
22 <span c l a s s=” p a n e l ”>
23 <span i d=” v u e D e t a i l ”>

117
Rémy Malgouyres, http://malgouyres.org Programmation Web Côté Client, JS et jQuery

24 </span><br /><br />


25 </span>
26 <span i d=”spanMainForm” c l a s s=” p a n e l ”>
27 <form i d=” ajouterPersonneForm ” method=” p o s t ” ></form>
28 <form i d=” modifierPersonneForm ” method=” p o s t ” ></form>
29 <form i d=” a j o u te r A d r e sse Fo r m ” method=” p o s t ” ></form>
30 <form i d=” modifierAdresseForm ” method=” p o s t ” ></form>
31 </span>
32
33 <!−− I n c l u s i o n de jQuery l e p l u s t r a d p o s s i b l e −−>
34 <s c r i p t s r c=” . / j q u e r y . j s ”></s c r i p t>
35 <s c r i p t s r c=” . / guiJQueryEventsPersonne . j s ”></s c r i p t>
36 <s c r i p t s r c=” . / g u i J Q u e r y E v e n t s A d r e s s e . j s ”></s c r i p t>
37
38 <!−− Ajout d ’ un main e t ex é c u t i o n −−>
39 <s c r i p t>
40 /* *
41 * Sé r i e d ’ i n s t r u c t i o n s e f f e c t u é e s pour i n i t i a l i s e r l ’ a p p l i c a t i o n /
42 * @method mainFunction
43 * @augments myApp
44 */
45 myApp . addModule ( ” mainFunction ” , function ( ) {
46
47 myApp . addModule . apply (myApp, [ ” modele ” , {
48 s e l e c t e d P e r s o n n e : null ,
49 personnes : [ ] ,
50 }]) ;
51
52
53 // Charger l e modèle :
54 myApp . g u i . m e d ia t o r . p u b l i s h ( ” pe r so nn e / rea d ” , {
55 p e r s o n n e : myApp . modele . s e l e c t e d P e r s o n n e
56 }) ;
57 }) ;
58
59 // ///////////////////////////////////////////////////
60 // Exé c u t i o n du Main a v e c un t e s t d ’ e x c e p t i o n
61 // t r y {
62 // Exé c u t i o n de l a mé t h o d e mainFunction
63 myApp . mainFunction ( ) ;
64 // } c a t c h ( e ) {
65 // a l e r t ( e . message ) ;
66 // }
67 </s c r i p t>
68 </body>
69 </html>

6.5.2 Création, Mise à jour, et suppression des personnes

exemples/clientServer/ex11_persistanceCreatePersonne.js
1 /* *
2 * Dé f i n i t i o n e t e n r e g i s t r e m e n t d e s c a l l b a c k s de c r é a t i o n d ’ une pe r so nne
3 * s u r l e s e r v e u r par r e q u ê t e AJAX.
4 */

118
Chapitre 6 : Requêtes Asynchrones et API Restful

5 myApp . addModule . apply (myApp . gui , [ ” c a l l b a c k s C r e a t e P e r s o n n e Q u e r y S e r v e r ” , function


() {
6
7 /* *
8 * Mé t h o d e c a l l b a c k q u i e s t a p p e l é e en c a s de s u c c è s de l a r e q u ê t e AJAX.
9 * C e t t e mé t h o d e i n f o r m e simplement l ’ u t i l i s a t e u r d e s é v e n t u e l l e s e r r e u r s .
10 * En e f f e t , l a r e q u ê t e n ’ e s t pas s u p p o s é e r e t o u r n e r d e s donn é e s .
11 */
12 var a j a x C a l l b a c k S u c c e s s = function ( r e t r i e v e d D a t a ) {
13 var concatErrorMsg=” ” ;
14 i f ( r e t r i e v e d D a t a [ ” e r r o r ” ] !== null ) {
15 for ( var key in r e t r i e v e d D a t a [ ’ e r r o r ’ ] ) {
16 i f ( r e t r i e v e d D a t a [ ’ e r r o r ’ ] . hasOwnProperty ( key ) ) {
17 concatErrorMsg += key + ” : ” + r e t r i e v e d D a t a [ ’ e r r o r ’ ] [ key ] + ” \n” ;
18 }
19 }
20 a l e r t ( concatErrorMsg ) ;
21 }
22 };
23
24 /* *
25 * Mé t h o d e a p p e l é e en c a s d ’ e r r e u r de l a r e q u ê t e AJAX e l l e même .
26 */
27 var a j a x C a l l b a c k E r r o r = function ( r e t r i e v e d D a t a ) {
28 a l e r t ( ” Erreur : é c h e c de l a r e q u ê t e a j a x ” ) ;
29 };
30
31 /* *
32 * C a l l b a c k a p p e l é l o r s de l ’ é v é nement ” p e r s o nn e / rea d ” du mé d i a t o r .
33 * E f f e c t u e une r e q u ê t e AJAX pour r é cup é r e r t o u t e s l e s p e r s o n n e s
34 * pour r e c o n s t r u i r e l e modèle de donn é e s .
35 */
36 var c r e a t e P e r s o n n e = function ( c o nt e x tA r g ) {
37
38 // r e q u ê t e AJAX g e t cod é en JSON
39 var j q x h r = $ . a j a x ( {
40 dataType : ” j s o n ” , // On e n v o i e l e s donn é e s l a p e r so nne cod é e en JSON
41 u r l : ” h t t p :// p r o g j s / e x e m p l e s / c l i e n t S e r v e r / a p i /” , // URL du s e r v e u r
42 method : ’ p o s t ’ , // Envoyer l e s donn é e s dans l e t a b l e a u $_POST
43 contentType : ’ a p p l i c a t i o n /x−www−form−u r l e n c o d e d ’ ,
44 // donn é e s à t r a n s m e t t r e au s e r v e u r
45 data : {
46 a c t i o n : ” personne−c r e a t e ” ,
47 p e r s o n n e : { // P r o p r i é t é s de l a p e r s o nn e
48 id : contextArg . personne . getProperty ( ” id ” ) ,
49 nom : c o nt e x tA r g . p e r s o n n e . g e t P r o p e r t y ( ”nom” )
50 }
51 },
52 // Mé t h o d e c a l l b a c k q u i r e c o n s t r u i t l e modèle en c a s de s u c c è s
53 success : ajaxCallbackSuccess ,
54 // Mé t h o d e c a l l b a c k q u i g è r e une é v é e n t u e l l e e r r e u r dans l a r e q u ê t e
55 error : ajaxCallbackError
56 }) ;
57
58 };
59 // E n r e g i s t r e m e n t du c a l l b a c k de l ’ é v é nement de mise à j o u r de l a pe r so nn e

119
Rémy Malgouyres, http://malgouyres.org Programmation Web Côté Client, JS et jQuery

60 myApp . g u i . m e d i a t o r . s u b s c r i b e ( ” p e r so n ne / c r e a t e d ” , c r e a t e P e r s o n n e ) ;
61
62 }() ] ) ;

exemples/clientServer/ex12_persistanceUpdatePersonne.js
1 /* *
2 * Dé f i n i t i o n e t e n r e g i s t r e m e n t d e s c a l l b a c k s de m o d i f i c a t i o n d ’ une pe r so nn e
3 * s u r l e s e r v e u r par r e q u ê t e AJAX.
4 */
5 myApp . addModule . apply (myApp . gui , [ ” c a l l b a c k s U p d a t e P e r s o n n e Q u e r y S e r v e r ” , function
() {
6
7 /* *
8 * Mé t h o d e c a l l b a c k q u i e s t a p p e l é e en c a s de s u c c è s de l a r e q u ê t e AJAX.
9 * C e t t e mé t h o d e i n f o r m e simplement l ’ u t i l i s a t e u r d e s é v e n t u e l l e s e r r e u r s .
10 * En e f f e t , l a r e q u ê t e n ’ e s t pas s u p p o s é e r e t o u r n e r d e s donn é e s .
11 */
12 var a j a x C a l l b a c k S u c c e s s = function ( r e t r i e v e d D a t a ) {
13 var concatErrorMsg=” ” ;
14 i f ( r e t r i e v e d D a t a [ ” e r r o r ” ] !== null ) {
15 for ( var key in r e t r i e v e d D a t a [ ’ e r r o r ’ ] ) {
16 i f ( r e t r i e v e d D a t a [ ’ e r r o r ’ ] . hasOwnProperty ( key ) ) {
17 concatErrorMsg += key + ” : ” + r e t r i e v e d D a t a [ ’ e r r o r ’ ] [ key ] + ” \n” ;
18 }
19 }
20 a l e r t ( concatErrorMsg ) ;
21 }
22 };
23
24 /* *
25 * Mé t h o d e a p p e l é e en c a s d ’ e r r e u r de l a r e q u ê t e AJAX e l l e même .
26 */
27 var a j a x C a l l b a c k E r r o r = function ( r e t r i e v e d D a t a ) {
28 a l e r t ( ” Erreur : é c h e c de l a r e q u ê t e a j a x ” ) ;
29 };
30
31 /* *
32 * C a l l b a c k a p p e l é l o r s de l ’ é v é nement ” p e r s o nn e / rea d ” du mé d i a t o r .
33 * E f f e c t u e une r e q u ê t e AJAX pour r é cup é r e r t o u t e s l e s p e r s o n n e s
34 * pour r e c o n s t r u i r e l e modèle de donn é e s .
35 */
36 var updatePersonne = function ( c o nt e x tA r g ) {
37
38 // r e q u ê t e AJAX g e t cod é en JSON
39 var j q x h r = $ . a j a x ( {
40 dataType : ” j s o n ” , // On e n v o i e l e s donn é e s l a p e r so nne cod é e en JSON
41 u r l : ” h t t p :// p r o g j s / e x e m p l e s / c l i e n t S e r v e r / a p i /” , // URL du s e r v e u r
42 method : ’ p o s t ’ , // Envoyer l e s donn é e s dans l e t a b l e a u $_POST
43 contentType : ’ a p p l i c a t i o n /x−www−form−u r l e n c o d e d ’ ,
44 // donn é e s à t r a n s m e t t r e au s e r v e u r
45 data : {
46 a c t i o n : ” personne−u p d a t e ” ,
47 p e r s o n n e : { // P r o p r i é t é s de l a p e r s o nn e
48 id : contextArg . personne . getProperty ( ” id ” ) ,
49 nom : c o nt e x tA r g . p e r s o n n e . g e t P r o p e r t y ( ”nom” )

120
Chapitre 6 : Requêtes Asynchrones et API Restful

50 }
51 },
52 // Mé t h o d e c a l l b a c k q u i r e c o n s t r u i t l e modèle en c a s de s u c c è s
53 success : ajaxCallbackSuccess ,
54 // Mé t h o d e c a l l b a c k q u i g è r e une é v é e n t u e l l e e r r e u r dans l a r e q u ê t e
55 error : ajaxCallbackError
56 }) ;
57
58 };
59 // E n r e g i s t r e m e n t du c a l l b a c k de l ’ é v é nement de mise à j o u r de l a pe r so nn e
60 myApp . g u i . m e d i a t o r . s u b s c r i b e ( ” p e r so n ne / u p d a t e ” , updatePersonne ) ;
61
62 }() ] ) ;

exemples/clientServer/ex13_persistanceDeletePersonne.js
1 /* *
2 * Dé f i n i t i o n e t e n r e g i s t r e m e n t d e s c a l l b a c k s de s u p p r e s s i o n d ’ une p e r s o nn e
3 * s u r l e s e r v e u r par r e q u ê t e AJAX.
4 */
5 myApp . addModule . apply (myApp . gui , [ ” c a l l b a c k s D e l e t e P e r s o n n e Q u e r y S e r v e r ” , function
() {
6
7 /* *
8 * Mé t h o d e a p p e l é e en c a s d ’ e r r e u r de l a r e q u ê t e AJAX e l l e même .
9 */
10 var a j a x C a l l b a c k E r r o r = function ( r e t r i e v e d D a t a ) {
11 a l e r t ( ” Erreur : é c h e c de l a r e q u ê t e a j a x ” ) ;
12 };
13
14 /* *
15 * C a l l b a c k a p p e l é l o r s de l ’ é v é nement ” p e r s o nn e / rea d ” du mé d i a t o r .
16 * E f f e c t u e une r e q u ê t e AJAX pour r é cup é r e r t o u t e s l e s p e r s o n n e s
17 * pour r e c o n s t r u i r e l e modèle de donn é e s .
18 */
19 var d e l e t e P e r s o n n e = function ( c o nt e x tA r g ) {
20
21 // r e q u ê t e AJAX g e t cod é en JSON
22 var j q x h r = $ . a j a x ( {
23 dataType : ” j s o n ” , // On e n v o i e l e s donn é e s l a p e r so nne cod é e en JSON
24 u r l : ” h t t p :// p r o g j s / e x e m p l e s / c l i e n t S e r v e r / a p i /” , // URL du s e r v e u r
25 method : ’ p o s t ’ , // Envoyer l e s donn é e s dans l e t a b l e a u $_POST
26 contentType : ’ a p p l i c a t i o n /x−www−form−u r l e n c o d e d ’ ,
27 // donn é e s à t r a n s m e t t r e au s e r v e u r
28 data : {
29 a c t i o n : ” personne−d e l e t e ” ,
30 i d : c o nt e x tA r g . p e r s o n n e . g e t P r o p e r t y ( ” i d ” ) ,
31 },
32 // Mé t h o d e c a l l b a c k q u i g è r e une é v é e n t u e l l e e r r e u r dans l a r e q u ê t e
33 error : ajaxCallbackError
34 }) ;
35
36 };
37 // E n r e g i s t r e m e n t du c a l l b a c k de l ’ é v é nement de mise à j o u r de l a pe r so nn e
38 myApp . g u i . m e d i a t o r . s u b s c r i b e ( ” p e r so n ne / d e l e t e ” , d e l e t e P e r s o n n e ) ;
39

121
Rémy Malgouyres, http://malgouyres.org Programmation Web Côté Client, JS et jQuery

40 }() ] ) ;

6.5.3 Création, Mise à jour, et suppression des adresses

exemples/clientServer/ex14_persistanceCreateAdresse.js
1 /* *
2 * Dé f i n i t i o n e t e n r e g i s t r e m e n t d e s c a l l b a c k s de c r é a t i o n d ’ une pe r so nne
3 * s u r l e s e r v e u r par r e q u ê t e AJAX.
4 */
5 myApp . addModule . apply (myApp . gui , [ ” c a l l b a c k s C r e a t e A d r e s s e Q u e r y S e r v e r ” , function
() {
6
7 /* *
8 * Mé t h o d e c a l l b a c k q u i e s t a p p e l é e en c a s de s u c c è s de l a r e q u ê t e AJAX.
9 * C e t t e mé t h o d e i n f o r m e simplement l ’ u t i l i s a t e u r d e s é v e n t u e l l e s e r r e u r s .
10 * En e f f e t , l a r e q u ê t e n ’ e s t pas s u p p o s é e r e t o u r n e r d e s donn é e s .
11 */
12 var a j a x C a l l b a c k S u c c e s s = function ( r e t r i e v e d D a t a ) {
13 var concatErrorMsg=” ” ;
14 i f ( r e t r i e v e d D a t a [ ” e r r o r ” ] !== null ) {
15 for ( var key in r e t r i e v e d D a t a [ ’ e r r o r ’ ] ) {
16 i f ( r e t r i e v e d D a t a [ ’ e r r o r ’ ] . hasOwnProperty ( key ) ) {
17 concatErrorMsg += key + ” : ” + r e t r i e v e d D a t a [ ’ e r r o r ’ ] [ key ] + ” \n” ;
18 }
19 }
20 a l e r t ( concatErrorMsg ) ;
21 }
22 };
23
24 /* *
25 * Mé t h o d e a p p e l é e en c a s d ’ e r r e u r de l a r e q u ê t e AJAX e l l e même .
26 */
27 var a j a x C a l l b a c k E r r o r = function ( r e t r i e v e d D a t a ) {
28 a l e r t ( ” Erreur : é c h e c de l a r e q u ê t e a j a x ” ) ;
29 };
30
31 /* *
32 * C a l l b a c k a p p e l é l o r s de l ’ é v é nement ” p e r s o nn e / rea d ” du mé d i a t o r .
33 * E f f e c t u e une r e q u ê t e AJAX pour r é cup é r e r t o u t e s l e s p e r s o n n e s
34 * pour r e c o n s t r u i r e l e modèle de donn é e s .
35 */
36 var c r e a t e A d r e s s e = function ( c o n te x t Ar g ) {
37
38 // r e q u ê t e AJAX g e t cod é en JSON
39 var j q x h r = $ . a j a x ( {
40 dataType : ” j s o n ” , // On e n v o i e l e s donn é e s l a p e r so nne cod é e en JSON
41 u r l : ” h t t p :// p r o g j s / e x e m p l e s / c l i e n t S e r v e r / a p i /” , // URL du s e r v e u r
42 method : ’ p o s t ’ , // Envoyer l e s donn é e s dans l e t a b l e a u $_POST
43 contentType : ’ a p p l i c a t i o n /x−www−form−u r l e n c o d e d ’ ,
44 // donn é e s à t r a n s m e t t r e au s e r v e u r
45 data : {
46 a c t i o n : ” a d r e s s e −c r e a t e ” ,
47 a d r e s s e : { // P r o p r i é t é s de l ’ a d r e s s e
48 id : contextArg . a d r e s s e . getProperty ( ” id ” ) ,

122
Chapitre 6 : Requêtes Asynchrones et API Restful

49 i d P e r s o n n e : c on t e x t A r g . p e r s o n n e . g e t P r o p e r t y ( ” i d ” ) ,
50 numeroRue : c o nt e xt A r g . a d r e s s e . g e t P r o p e r t y ( ”numeroRue” ) ,
51 r u e : c on t e x t A r g . a d r e s s e . g e t P r o p e r t y ( ” rue ” ) ,
52 c o d e P o s t a l : c on t e x t A r g . a d r e s s e . g e t P r o p e r t y ( ” c o d e P o s t a l ” ) ,
53 v i l l e : c o n te x t Ar g . a d r e s s e . g e t P r o p e r t y ( ” v i l l e ” ) ,
54 pays : c on t e xt A r g . a d r e s s e . g e t P r o p e r t y ( ” pays ” )
55 }
56 },
57 // Mé t h o d e c a l l b a c k q u i r e c o n s t r u i t l e modèle en c a s de s u c c è s
58 success : ajaxCallbackSuccess ,
59 // Mé t h o d e c a l l b a c k q u i g è r e une é v é e n t u e l l e e r r e u r dans l a r e q u ê t e
60 error : ajaxCallbackError
61 }) ;
62
63 };
64 // E n r e g i s t r e m e n t du c a l l b a c k de l ’ é v é nement de mise à j o u r de l a pe r so nn e
65 myApp . g u i . m e d i a t o r . s u b s c r i b e ( ” a d r e s s e / c r e a t e d ” , c r e a t e A d r e s s e ) ;
66
67 }() ] ) ;

exemples/clientServer/ex15_persistanceUpdateAdresse.js
1 /* *
2 * Dé f i n i t i o n e t e n r e g i s t r e m e n t d e s c a l l b a c k s de c r é a t i o n d ’ une pe r so nne
3 * s u r l e s e r v e u r par r e q u ê t e AJAX.
4 */
5 myApp . addModule . apply (myApp . gui , [ ” c a l l b a c k s U p d a t e A d r e s s e Q u e r y S e r v e r ” , function
() {
6
7 /* *
8 * Mé t h o d e c a l l b a c k q u i e s t a p p e l é e en c a s de s u c c è s de l a r e q u ê t e AJAX.
9 * C e t t e mé t h o d e i n f o r m e simplement l ’ u t i l i s a t e u r d e s é v e n t u e l l e s e r r e u r s .
10 * En e f f e t , l a r e q u ê t e n ’ e s t pas s u p p o s é e r e t o u r n e r d e s donn é e s .
11 */
12 var a j a x C a l l b a c k S u c c e s s = function ( r e t r i e v e d D a t a ) {
13 var concatErrorMsg=” ” ;
14 i f ( r e t r i e v e d D a t a [ ” e r r o r ” ] !== null ) {
15 for ( var key in r e t r i e v e d D a t a [ ’ e r r o r ’ ] ) {
16 i f ( r e t r i e v e d D a t a [ ’ e r r o r ’ ] . hasOwnProperty ( key ) ) {
17 concatErrorMsg += key + ” : ” + r e t r i e v e d D a t a [ ’ e r r o r ’ ] [ key ] + ” \n” ;
18 }
19 }
20 a l e r t ( concatErrorMsg ) ;
21 }
22 };
23
24 /* *
25 * Mé t h o d e a p p e l é e en c a s d ’ e r r e u r de l a r e q u ê t e AJAX e l l e même .
26 */
27 var a j a x C a l l b a c k E r r o r = function ( r e t r i e v e d D a t a ) {
28 a l e r t ( ” Erreur : é c h e c de l a r e q u ê t e a j a x ” ) ;
29 };
30
31 /* *
32 * C a l l b a c k a p p e l é l o r s de l ’ é v é nement ” p e r s o nn e / rea d ” du mé d i a t o r .
33 * E f f e c t u e une r e q u ê t e AJAX pour r é cup é r e r t o u t e s l e s p e r s o n n e s

123
Rémy Malgouyres, http://malgouyres.org Programmation Web Côté Client, JS et jQuery

34 * pour r e c o n s t r u i r e l e modèle de donn é e s .


35 */
36 var u p d a t e A d r e s s e = function ( c o n te x t Ar g ) {
37
38 // r e q u ê t e AJAX g e t cod é en JSON
39 var j q x h r = $ . a j a x ( {
40 dataType : ” j s o n ” , // On e n v o i e l e s donn é e s l a p e r so nne cod é e en JSON
41 u r l : ” h t t p :// p r o g j s / e x e m p l e s / c l i e n t S e r v e r / a p i /” , // URL du s e r v e u r
42 method : ’ p o s t ’ , // Envoyer l e s donn é e s dans l e t a b l e a u $_POST
43 contentType : ’ a p p l i c a t i o n /x−www−form−u r l e n c o d e d ’ ,
44 // donn é e s à t r a n s m e t t r e au s e r v e u r
45 data : {
46 a c t i o n : ” a d r e s s e −u p d a t e ” ,
47 a d r e s s e : { // P r o p r i é t é s de l ’ a d r e s s e
48 id : contextArg . a d r e s s e . getProperty ( ” id ” ) ,
49 i d P e r s o n n e : c on t e x t A r g . p e r s o n n e . g e t P r o p e r t y ( ” i d ” ) ,
50 numeroRue : c o nt e xt A r g . a d r e s s e . g e t P r o p e r t y ( ”numeroRue” ) ,
51 r u e : c on t e x t A r g . a d r e s s e . g e t P r o p e r t y ( ” rue ” ) ,
52 c o d e P o s t a l : c on t e x t A r g . a d r e s s e . g e t P r o p e r t y ( ” c o d e P o s t a l ” ) ,
53 v i l l e : c o n te x t Ar g . a d r e s s e . g e t P r o p e r t y ( ” v i l l e ” ) ,
54 pays : c on t e xt A r g . a d r e s s e . g e t P r o p e r t y ( ” pays ” )
55 }
56 },
57 // Mé t h o d e c a l l b a c k q u i r e c o n s t r u i t l e modèle en c a s de s u c c è s
58 success : ajaxCallbackSuccess ,
59 // Mé t h o d e c a l l b a c k q u i g è r e une é v é e n t u e l l e e r r e u r dans l a r e q u ê t e
60 error : ajaxCallbackError
61 }) ;
62
63 };
64 // E n r e g i s t r e m e n t du c a l l b a c k de l ’ é v é nement de mise à j o u r de l a pe r so nn e
65 myApp . g u i . m e d i a t o r . s u b s c r i b e ( ” a d r e s s e / changed ” , u p d a t e A d r e s s e ) ;
66
67 }() ] ) ;

exemples/clientServer/ex16_persistanceDeleteAdresse.js
1 /* *
2 * Dé f i n i t i o n e t e n r e g i s t r e m e n t d e s c a l l b a c k s de c r é a t i o n d ’ une pe r so nne
3 * s u r l e s e r v e u r par r e q u ê t e AJAX.
4 */
5 myApp . addModule . apply (myApp . gui , [ ” c a l l b a c k s D e l e t e A d r e s s e Q u e r y S e r v e r ” , function
() {
6
7 /* *
8 * Mé t h o d e c a l l b a c k q u i e s t a p p e l é e en c a s de s u c c è s de l a r e q u ê t e AJAX.
9 * C e t t e mé t h o d e i n f o r m e simplement l ’ u t i l i s a t e u r d e s é v e n t u e l l e s e r r e u r s .
10 * En e f f e t , l a r e q u ê t e n ’ e s t pas s u p p o s é e r e t o u r n e r d e s donn é e s .
11 */
12 var a j a x C a l l b a c k S u c c e s s = function ( r e t r i e v e d D a t a ) {
13 var concatErrorMsg=” ” ;
14 i f ( r e t r i e v e d D a t a [ ” e r r o r ” ] !== null ) {
15 for ( var key in r e t r i e v e d D a t a [ ’ e r r o r ’ ] ) {
16 i f ( r e t r i e v e d D a t a [ ’ e r r o r ’ ] . hasOwnProperty ( key ) ) {
17 concatErrorMsg += key + ” : ” + r e t r i e v e d D a t a [ ’ e r r o r ’ ] [ key ] + ” \n” ;
18 }

124
Chapitre 6 : Requêtes Asynchrones et API Restful

19 }
20 a l e r t ( concatErrorMsg ) ;
21 }
22 };
23
24 /* *
25 * Mé t h o d e a p p e l é e en c a s d ’ e r r e u r de l a r e q u ê t e AJAX e l l e même .
26 */
27 var a j a x C a l l b a c k E r r o r = function ( r e t r i e v e d D a t a ) {
28 a l e r t ( ” Erreur : é c h e c de l a r e q u ê t e a j a x ” ) ;
29 };
30
31 /* *
32 * C a l l b a c k a p p e l é l o r s de l ’ é v é nement ” p e r s o nn e / rea d ” du mé d i a t o r .
33 * E f f e c t u e une r e q u ê t e AJAX pour r é cup é r e r t o u t e s l e s p e r s o n n e s
34 * pour r e c o n s t r u i r e l e modèle de donn é e s .
35 */
36 var d e l e t e A d r e s s e = function ( c o n te x t Ar g ) {
37
38 // r e q u ê t e AJAX g e t cod é en JSON
39 var j q x h r = $ . a j a x ( {
40 dataType : ” j s o n ” , // On e n v o i e l e s donn é e s l a p e r so nne cod é e en JSON
41 u r l : ” h t t p :// p r o g j s / e x e m p l e s / c l i e n t S e r v e r / a p i /” , // URL du s e r v e u r
42 method : ’ p o s t ’ , // Envoyer l e s donn é e s dans l e t a b l e a u $_POST
43 contentType : ’ a p p l i c a t i o n /x−www−form−u r l e n c o d e d ’ ,
44 // donn é e s à t r a n s m e t t r e au s e r v e u r
45 data : {
46 a c t i o n : ” a d r e s s e −d e l e t e ” ,
47 i d : c o nt e x tA r g . a d r e s s e . g e t P r o p e r t y ( ” i d ” ) ,
48 },
49 // Mé t h o d e c a l l b a c k q u i r e c o n s t r u i t l e modèle en c a s de s u c c è s
50 success : ajaxCallbackSuccess ,
51 // Mé t h o d e c a l l b a c k q u i g è r e une é v é e n t u e l l e e r r e u r dans l a r e q u ê t e
52 error : ajaxCallbackError
53 }) ;
54
55 };
56 // E n r e g i s t r e m e n t du c a l l b a c k de l ’ é v é nement de mise à j o u r de l a pe r so nn e
57 myApp . g u i . m e d i a t o r . s u b s c r i b e ( ” a d r e s s e / d e l e t e ” , d e l e t e A d r e s s e ) ;
58
59 }() ] ) ;

125
Annexe A

Graphisme avec les Canvas HTML5

A.1 Notion de canvas


Les canvas HTML5 fournissent une petite API graphique 2D en javascript qui permet de
réaliser des dessins, des graphiques, etc. sans plugin. Les canvas 2D sont dores et déjà disponible
sur tous les grands navigateurs. L’extension webGL (qui dépasse le cadre de ce cours) permet
de faire des affichage de scènes 3D en accédant aux fonctionnalités d’OpenGL via les shaders
en GLSL. L’extension webGL est implémentée dans tous les Grands Navigateurs mais n’est pas
implémentée à ce jour dans internet explorer car l’éditeur de ce navigateur préfère privilégier
une solution propriétaire.
Voici un exemple avec un canvas qui dessine un triangle.
exemples/canvas/ex01_triangle.html
1 /<! d o c t y p e HTML>
2 <html lang=” f r ”>
3 <head>
4 <meta charset=”UTF−8” />
5 <t i t l e>Mon p r e m i e r canvas HTML5</ t i t l e>
6 </head>
7 <body>
8 <!−− Dé c l a r a t i o n d’un canvas v i d e avec son id −−>
9 <canvas id=”monCanvas” width=” 2000 ” height=” 1000 ” style= ” position :a b s o l u t e ; ”
></canvas>
10 <s c r i p t>
11 // On r é c u p è r e l e canvas pour d e s s i n e r
12 var myCanvas = document . getElementById ( ”monCanvas” ) ;
13 // On r é c u p è r e un c o n t e x t e du canvas pour u t i l i s e r l e s mé t h o d e s de
dessin
14 var c o n t e x t = myCanvas . g e t C o n t e x t ( ”2d” ) ;
15 // c o u l e u r de r e m p l i s s a g e r o u g e
16 c o n t e x t . f i l l S t y l e = ”#FF0000” ;
17
18 c o n t e x t . beginPath ( ) ;
19 c o n t e x t . moveTo ( 1 0 , 1 0 ) ;
20 context . lineTo (100 , 100) ;
21 context . lineTo (190 , 10) ;
22 context . lineTo (10 , 10) ;
23
24 context . f i l l () ;
25 context . closePath () ;

126
Chapitre A : Graphisme avec les Canvas HTML5

26 </s c r i p t>
27 <h1>Page HTML avec un canvas</h1>
28 <p>
29 </p>
30 </body>
31 </html>

A.2 Exemple d’animation dans un canvas


Voici un exemple qui réalise une animation à l’aide d’un timer qui exécute la fonction animate
toutes les 20ms, soit 50 fois par seconde.
exemples/canvas/ex02_animation.html
1 /<! d o c t y p e HTML>
2 <html lang=” f r ”>
3 <head>
4 <meta charset=”UTF−8” />
5 <t i t l e>Mon p r e m i e r canvas HTML5</ t i t l e>
6 </head>
7 <body>
8 <!−− Dé c l a r a t i o n d’un canvas v i d e avec son id −−>
9 <canvas id=”monCanvas” width=” 2000 ” height=” 1000 ” style= ” position :a b s o l u t e ; ”
></canvas>
10 <s c r i p t>
11 var t i m e r = s e t I n t e r v a l ( animate , 2 0 ) ;
12
13 function animate ( ) {
14
15 // On r é c u p è r e l e canvas pour d e s s i n e r
16 var canvas = document . getElementById ( ”monCanvas” ) ;
17 // On r é c u p è r e un c o n t e x t e du canvas pour u t i l i s e r l e s mé t h o d e s de
dessin
18 var c o n t e x t = canvas . g e t C o n t e x t ( ”2d” ) ;
19 // c o u l e u r de r e m p l i s s a g e r o u g e
20 c o n t e x t . f i l l S t y l e = ”#FF0000” ;
21 c o n t e x t . beginPath ( ) ;
22 var d = new Date ( ) ;
23 var n = d . getTime ( ) ;
24 // nombre de m i l l i s e c o n d e s d e p u i s l e 01 /01/1970
25
26 var s e c = n / 1 0 0 0 . 0 ;
27 c o n t e x t . c l e a r Rect ( 0 , 0 , canvas . width , canvas . height ) ;
28
29 context . save ( ) ;
30 c o n t e x t . t r a n s l a t e (200+500 * (1+Math . c o s ( 0 . 5 * s e c ) ) , 200+200 *(1.0+
Math . s i n ( s e c ) ) ) ;
31 // l ’ a n g l e de r o t a t i o n d o i t ê t r e e n t r e 0 e t 2*Math . P I ’
32 c o n t e x t . r o t a t e ( s e c − 2*Math . PI *Math . round ( s e c / ( 2 * Math . PI ) ) ) ;
33 c o n t e x t . moveTo ( 0 , 0 ) ;
34 context . lineTo (100 , 100) ;
35 context . lineTo (200 , 0) ;
36 context . lineTo (0 , 0) ;
37
38 context . f i l l () ;

127
Rémy Malgouyres, http://malgouyres.org Programmation Web Côté Client, JS et jQuery

39 context . closePath () ;
40 context . r e s t o r e () ;
41 }
42 </s c r i p t>
43 <h1>Page HTML avec un canvas</h1>
44 <p>
45
46 </p>
47 </body>
48 </html>

128
Annexe B

Programmation Événementielle en
JavaScript

B.1 Rappel sur la Gestion d’Événements en CSS


Dans un style CSS, on peut mettre des styles différents sur une balise HTML donnée, suivant
le contexte utilisateur, via la notion d’événement. Dans l’exmple suivant, le style d’un lien est
modifié suivant que le lien a déja été cliqué, ou si la souris survolle le lien (événement hover).

1 /* s t y l e par d é f a u t d e s l i e n s */
2 a :link {
3 text−decoration : none ;
4 color : #00e ; /* b l e u c l a i r */
5 }
6 /* s t y l e d e s l i e n s v i s i t é s */
7 a :visited {
8 text−decoration : none ;
9 color : #c 0 c ; /* mauve */
10 }
11 /* s t y l e d e s l i e n s v i s i t é s */
12 a :hover {
13 text−decoration : u n d e r l i n e ; /* s o u l i g n é */
14 color : #e40 ; /* r o u g e v i f */
15 }

Voici un autre exemple, dans lequel un élément HTML (ici une balise <span> et son contenu)
apparaît en popup pour afficher les détails d’une personne lors du survol de nom de la personne.
La balise span (au sein d’un paragraphe d’une classe CSS spécifique appelé popupDetails)
est par défaut invisible (propriété display à none). Cette même balise span devient visible
lorsque le paragraphe est survollé.

workspace_progWeb_2a/events/ex01_popup_html_css.html
1 <! doctype html>
2 <html l a n g=” f r ”>
3 <head>
4 <meta c h a r s e t=” u t f −8” />
5 <l i nk r e l=” s t y l e s h e e t ” h r e f=” . / m yStyl e . c s s ” />
6 <s tyl e>

129
Rémy Malgouyres, http://malgouyres.org Programmation Web Côté Client, JS et jQuery

7 body {
8 font −family : ”Comic Sans MS” ;
9 font−s i z e : 120% ;
10 }
11 h1{
12 margin : 0 auto ;
13 text −align : c e n t e r ;
14 }
15 p . popupDetails {
16 background−color : y e l l o w ;
17 position : r e l a t i v e ; /* pour position e r l e span en a b s o l u */
18 max−width : 200 px ;
19 }
20 p . p o p u p D e t a i l s span {
21 display : none ;
22 }
23 p . p o p u p D e t a i l s :hover span {
24 position : a b s o l u t e ;
25 l e f t : 200 px ;
26 top : −30 ;
27 min−width : 500 px ;
28 background−color : b l a c k ;
29 color : w h i t e ;
30 border−r a d i u s : 20 px ;
31 padding : 10 px ;
32 display : b l o c k ;
33 }
34 </s tyl e>
35 <t i t l e>Popups en HTML e t CSS</ t i t l e>
36 </head>
37 <body>
38 <!−− dé but du c o r p s HTML −−>
39 <h1><i>Popup</ i> en <i>HTML</ i> e t <i>CSS</ i></h1>
40 <p c l a s s=” p o p u p D e t a i l s ”>
41 S c a r l e t t Johansson
42 <span>né e l e 22 novembre 1984 à New York ,
43 e s t une a c t r i c e e t c h a n t e u s e amé r i c a i n e .<br />
44 ( s o u r c e&nbsp ; : w i k i p é d i a )
45 </span>
46 </p>
47 </body>
48 <!−− f i n du c o r p s HTML −−>
49 </html>
50 <!−− f i n du code HTML −−>

B.2 Événements en Javascript


B.2.1 Le principe des événements en Javascript
Les événements en Javascript permettent, en réponse à une événement sur un élément HTML
du document, d’appeler une fonction callback en Javascript. Ceci suffit à créer une interface
homme machine (IHM ) côté client, basée sur de la programmation événementielle en Javascript.
Une liste (non exhaustive ; Voir sur le web pour la liste complète)

130
Chapitre B : Programmation Événementielle en JavaScript

1. Événements souris

(a) onclick : sur un simple clic


(b) ondblclick : sur un double clic
(c) onmousedown : lorsque le bouton de la souris est enfoncé, sans forcément le relâcher
(d) onmousemove : lorsque la souris est déplacée
(e) onmouseout : lorsque la souris sort de l’élément
(f) onmouseover : lorsque la souris est sur l’élément
(g) onmouseup : lorsque le bouton de la souris est relâché

2. Événements clavier

(a) onkeydown : lorsqu’une touche est enfoncée


(b) onkeypress : lorsqu’une touche est pressée et relâchée
(c) onkeyup : lorsqu’une touche est relâchée

3. Événements formulaire

(a)
(b) onblur : à la perte du focus
(c) onchange : à la perte du focus si la valeur a changé
(d) onfocus : lorsque l’élément prend le focus (ou devient actif)
(e) onreset : lors de la remise à zéro du formulaire (via un bouton ”reset” ou une
fonction reset())
(f) onselect : quand du texte est sélectionné
(g) onsubmit : quand le formulaire est validé (via un bouton de type ”submit” ou une
fonction submit())

B.2.2 Exemple de mise à jour d’un élément

workspace_progWeb_2a/events/ex02_updateElementOnChange.html
1 <! doctype html>
2 <html l a n g=” f r ”>
3 <head>
4 <meta c h a r s e t=” u t f −8” />
5 <l i nk r e l=” s t y l e s h e e t ” h r e f=” . / m yStyl e . c s s ” />
6 <s tyl e>
7 body {
8 font −family : ”Comic Sans MS” ;
9 font−s i z e : 120% ;
10 }
11 h1{
12 margin : 0 auto ;
13 text −align : c e n t e r ;
14 }
15 </s tyl e>

131
Rémy Malgouyres, http://malgouyres.org Programmation Web Côté Client, JS et jQuery

16 <t i t l e>Mise à Jour Par Év é nement</ t i t l e>


17 </head>
18 <body>
19 <!−− dé but du c o r p s HTML −−>
20 <h1>Mise à Jour Par Év é nement <code>onchange</code></h1>
21 <p c l a s s=” p o p u p D e t a i l s ”>
22 <i nput i d=” myInputId ” type=” t e x t ” s i z e=” 15 ”
23 onchange=” f o n c t i o n M i s e A J o u r ( ’ myInputContent ’ , ’ myInputId ’ ) ” />
24 <br />
25 <span i d=” myInputContent ”></span>
26 </p>
27 <s c r i p t>
28 function f o n c t i o n M i s e A J o u r ( el e me ntId , i n p u t I d ) {
29 document . getElementById ( e l e m e n t I d ) . innerHTML
30 = document . getElementById ( i n p u t I d ) . v a l u e ;
31 }
32 </s c r i p t>
33 </body>
34 <!−− f i n du c o r p s HTML −−>
35 </html>
36 <!−− f i n du code HTML −−>

B.2.3 Formulaires Dynamiques an Javascript


Nous voyons ici un exemple d’utilisation du javascript pour créer un formulaire dont les attri-
buts dépendent de la valeur d’un premier champ. Lorsqu’on sélectionne “deuxième année”, un
nouveau champ apparaît. Pour celà, on utilise l’évennement onchange sur l’input de l’année,
qui est géré par la fonction anneeChange. On teste alors la valeur de l’attribut, puis le cas
échéant on génére un nouveau champ dans un div d’id attributSupplementaire.

workspace_progWeb_2a/events/formulaire_dynamique.html
1 <! doctype html>
2 <html l a n g=” f r ”>
3 <head>
4 <meta c h a r s e t=”UTF−8” />
5 <t i t l e>F o r m u l a i r e dynamique</ t i t l e>
6 </head>
7 <body>
8 <form method=” p o s t ” a c t i o n=” r e c e p t i o n . php ”>
9 <p>
10 <l a b e l f or=”nom”>Nom</ l a b e l><i nput name=”nom” i d=”nom” />

132
Chapitre B : Programmation Événementielle en JavaScript

11 </p>
12 <p>
13 <s e l e c t name=” annee ” i d=” annee ” p a t t e r n=” ( p r e m i e r e ) | ( deuxieme ) ”
onchange =’ anneeChange ( ) ; ’>
14 <option v a l u e=” c h o i s i s s e z ” s e l e c t e d d i s a b l e d>−− c h o i s i s s e z −−</option>
15 <option v a l u e=” p r e m i e r e ”>Première ann é e</option>
16 <option v a l u e=” deuxième ”>Deuxième ann é e</option>
17 </s e l e c t>
18 </p>
19 <div i d=” a t t r i b u t S u p p l e m e n t a i r e ”>
20
21 </div>
22 <p>
23 <i nput type=” s u b m i t ” v a l u e=”−− OK −−” />
24 </p>
25 </form>
26 <s c r i p t>
27 function anneeChange ( ) {
28 var pa r a gr a phe = document . getElementById ( ” a t t r i b u t S u p p l e m e n t a i r e ” ) ;
29 pa r ag r a phe . innerHTML=document . getElementById ( ” annee ” ) . v a l u e+” ann é e .<br />” ;
30 i f ( document . getElementById ( ” annee ” ) . v a l u e == ” deuxième ” ) {
31 par a gr aph e . innerHTML+=”<l a b e l>O r i e n t a t i o n pr é vue pour l ’ ann é e p r o c h a i n e
:</ l a b e l>”
32 +’<s e l e c t name=” o r i e n t a t i o n ” i d=” o r i e n t a t i o n ”> ’
33 +’<option v a l u e=”LP”>LP</option> ’
34 +’<option v a l u e=” master ”>master</option> ’
35 +”<option v a l u e =\” i n g e \”>E c o l e d ’ i n g é</option>”
36 +’<option v a l u e=” b o u l o t ”>Boulot</option> ’
37 +’<option v a l u e=” a u t r e ”>Autre</option> ’
38 +’</s e l e c t> ’ ;
39
40 }
41 }
42 anneeChange ( ) ;
43 </s c r i p t>
44 </body>
45 </html>

workspace_progWeb_2a/events/reception.php
1 <! doctype html>
2 <html l a n g=” f r ”>
3 <head>

133
Rémy Malgouyres, http://malgouyres.org Programmation Web Côté Client, JS et jQuery

4 <meta c h a r s e t=”UTF−8” />


5 <t i t l e>F o r m u l a i r e dynamique</ t i t l e>
6 </head>
7 <body>
8 <?php
9 $nom= ( i s s e t ($_POST [ ”nom” ] ) ) ? $_POST [ ”nom” ] : ”nom i n d é te r m i n é ” ;
10 $annee = ( i s s e t ($_POST [ ” annee ” ] ) ) ? $_POST [ ” annee ” ] : ”ann é e i n d é temin é e ” ;
11 echo ”Nom : ” . $nom . ”<br />” ;
12 echo ”Anné e : ” . $annee . ”<br />” ;
13 i f ( $annee==” deuxième ” )
14 echo ” O r i e n t a t i o n : ” . $_POST [ ” o r i e n t a t i o n ” ] ;
15
16
17 ?>
18 </body>
19 </html>

134
Annexe C

Gestion des fenêtres

C.1 Charger un nouveau document

workspace_progWeb_2a/window/ex01_classes_telephone.js
1 // c o n s t r u c t e u r
2 function Telephone ( t e l 1 ) {
3 // t e s t de t é l é phone f r a n ¸ a i s à 10 c h i f f r e s
4 // 1) su p p r i m e r l e s e s p a c e s , 2) t e s t e r l e s c h i f f r e s
5 i f ( t e l 1 . r e p l a c e ( / \ s /g , ’ ’ ) . match ( /^ ((\+33) | 0 ) [0 −9]{9} $/g ) )
6 t h i s . t e l 1=t e l 1 ;
7 else
8 throw new E r r o r ( ”Numé ro de t é l é phone i n v a l i d e ” ) ;
9 }
10
11 Telephone . p r o t o t y p e . a f f i c h e = function ( ) {
12 document . w r i t e ( ”Té l é phone 1 : ”+t h i s . t e l 1+”<br />” ) ;
13 }

workspace_progWeb_2a/window/ex01_loadNewDoc.html
1 <! doctype HTML>
2 <html l a n g=” f r ”>
3 <head>
4 <meta c h a r s e t=”UTF−8” />
5 <t i t l e>Charger un document</ t i t l e>
6 <s c r i p t s r c=” . / e x 0 1 _ c l a s s e s _ t e l e p h o n e . j s ”></s c r i p t>
7 </head>
8 <body>
9 <p>
10 <s c r i p t>
11 try {
12 var numero = prompt ( ” Merci d ’ e n t r e r un numé ro de t é l é phone en France mé
tropolitaine ”) ;
13 var t e l = new Telephone ( numero ) ;
14 tel . affiche () ;
15 } catch ( e r r ) {
16 l o c a t i o n = ” ex01_error . html ” ;
17 }
18 </s c r i p t>
19 <p>

135
Rémy Malgouyres, http://malgouyres.org Programmation Web Côté Client, JS et jQuery

20 </body>
21 </html>

workspace_progWeb_2a/window/ex01_error.html
1 <! doctype HTML>
2 <html l a n g=” f r ”>
3 <head>
4 <meta c h a r s e t=”UTF−8” />
5 <t i t l e>Charger un document</ t i t l e>
6 <s c r i p t s r c=” . / e x 1 0 _ c l a s s e s _ t e l e p h o n e . j s ”></s c r i p t>
7 </head>
8 <body>
9 <p>
10 Bonjour , I l s ’ e s t p r o d u i t une e r r e u r . Merci d ’ e n t r e r un numé r o v a l i d e .
11 S i l e problème p e r s i s t e , m e r c i de c o n t a c t e r l e s t a g i a i r e q u i a f a i t l e s i t e . . .
12 <button o n c l i c k=” l o c a t i o n = ’ ex01_loadNewDoc . html ’ ; ”>Retour à l a s a i s i e</button>
13 <p>
14 </body>
15 </html>

C.2 Naviguer dans l’historique


la propriété history a deux méthodes back() et forward() qui permettent respectivement
de reculer ou d’avancer dans l’historique.

workspace_progWeb_2a/window/ex02_history.html
1 <! doctype HTML>
2 <html l a n g=” f r ”>
3 <head>
4 <meta c h a r s e t=”UTF−8” />
5 <t i t l e>Charger un document</ t i t l e>
6 <s c r i p t s r c=” . / e x 1 0 _ c l a s s e s _ t e l e p h o n e . j s ”></s c r i p t>
7 </head>
8 <body>
9 <p>
10 Bonjour , bla , b l a . . .<br />
11 <a h r e f = ” e x 0 2 _ h i s t o r y B a c k . html ”>C l i q u e z i c i</a> pour a l l e r à l a page s u i v a n t e .
12 <p>
13 </body>
14 </html>

workspace_progWeb_2a/window/ex02_historyBack.html
1 <! doctype HTML>
2 <html l a n g=” f r ”>
3 <head>
4 <meta c h a r s e t=”UTF−8” />
5 <t i t l e>Charger un document</ t i t l e>
6 <s c r i p t s r c=” . / e x 1 0 _ c l a s s e s _ t e l e p h o n e . j s ”></s c r i p t>
7 </head>
8 <body>
9 <p>

136
Chapitre C : Gestion des fenêtres

10 Bla , b l a . . .<br />


11 Vous avez r a t é q u e l q u e c h o s e ?
12 <button o n c l i c k=” h i s t o r y . b a c k ( ) ; ”>Retour à l a page pr é c é d e n t e</button>
13 <p>
14 </body>
15 </html>

C.3 Ouvrir une nouvelle fenêtre (popup)

workspace_progWeb_2a/window/ex03_windowOpen.html
1 <! doctype HTML>
2 <html l a n g=” f r ”>
3 <head>
4 <meta c h a r s e t=”UTF−8” />
5 <t i t l e>Ouvrir un f e n ê t r e</ t i t l e>
6 <s c r i p t s r c=” . / e x 1 0 _ c l a s s e s _ t e l e p h o n e . j s ”></s c r i p t>
7 </head>
8 <body>
9 <p>
10 Bonjour , bla , b l a . . .
11 <button o n c l i c k=” window . open ( ’ ex03_windowPopup . html ’ , ’ma popup ’ , ’ width=400 ,
height =400 , r e s i z e a b l e=yes ’ ) ; ”>
12 Plus d ’ i n f o s
13 </button>
14 <p>
15 </body>
16 </html>

workspace_progWeb_2a/window/ex03_windowPopup.html
1 <! doctype HTML>
2 <html l a n g=” f r ”>
3 <head>
4 <meta c h a r s e t=”UTF−8” />
5 <t i t l e>Charger un document</ t i t l e>
6 <s c r i p t s r c=” . / e x 1 0 _ c l a s s e s _ t e l e p h o n e . j s ”></s c r i p t>
7 </head>
8 <body>
9 <p s t y l e=” font−s i z e : 100 ; text −align : c e n t e r ; ”>
10 Coucou !
11 <p>
12 <p>
13 <a h r e f=” j a v a s c r i p t :window . c l o s e ( ) ; ”>Fermer l a f e n ê t r e</a>
14 </p>
15 </body>
16 </html>

137
Annexe D

Document Object Model (DOM)

La programmation côté client permet de modifier certaines parties d’un document HTML
dans recharger toute la page. Il y a plusieurs avantages : on évite de surcharger le serveur et
le trafic réseau et on améliore la réactivité de l’application web pour le plus grand bonheur de
l’utilisateur.
Pour faire cela, le langage Javascript côté client fournit une structure de données permettant
d’accéder aux éléments du document HTML et de modifier les éléments du document HTML.
Cette structure de données s’appelle le Document Object Model, en abrégé DOM. Il existe
un DOM legacy qui s’est sédimenté informellement au travers des versions successives du
javascript en tenant compte des implémentations des différents navigateurs, qui collaboraient
plus ou moins bien pour être mutuellement compatibles. Il existe aussi le DOM tel qu’il a été
finalement spécifié par le W3C.
Les éléments du document HTML ayant, de par leur imbrication, une structure arbores-
cente, le DOM W3C a une structure d’arbre. On peut accèder et manipuler via un ensemble
de propriétés et de méthodes javascript, notamment de l’interface Document et de l’interface
Element et ses classes filles, qui permettent de manipulet les éléments (HTML entre autres)
du document.

D.1 Qu’est-ce que le DOM ?


Le Document Object Model (en abrégé DOM ) corrrespond à l’arborescence des imbrications des
balises HTML d’un document. Voici un fichier HTML simple et une représentation schématique
du DOM correspondant.
workspace_progWeb_2a/dom/ex01_documentHTML5.html
1 <! doctype HTML>
2 <html l a n g=” f r ”>
3 <head>
4 <meta c h a r s e t=”UTF−8” />
5 <t i t l e>Un document HTML5</ t i t l e>
6 </head>
7 <body>
8 <h1>Exemple de f i c h i e r <i>HTML5</ i></h1>
9 <p>
10 Un document <i>HTML5</ i> e s t une s t r u c t u r e a r b o r e s c e n t e .
11 <p>
12 </body>

138
Chapitre D : Document Object Model (DOM)

13 </html>

Document

<html>

<head> <body>

<title> <meta> <h1> <p>

"Un document HTML5" "Exemple de fichier" <i> "Un document" <i> "est une structure arborescente."

"HTML5" "HTML5"

Le DOM dont nous parlons ici est le DOM du W3C, qui est aujourd’hui supporté par tous
les grands navigateurs.
Le langage Javascript côté client propose une hiérarchie de classes pour parcourir et mani-
puler le DOM d’un document. Il s’agit essentiellement d’une structure de donnée d’arbre, où
chaque noeud (correspondant à une balise ou commentaire ou texte, etc. du document) possède
une collection de noeuds fils, qui sont les éléments ou structures imbriquées.
La bibliothèque jQuery permet un accès plus haut niveau au DOM pour sonder et manipuler
le code du document.

D.2 Sélection et Manipulation de Base sur le DOM


D.2.1 Sélection de tout ou partie des éléments
L’exemple suivant cherche tous les éléments du document et affiche leur nom de balise (tagName
ou nodeName). On apprend aussi à ajouter du code HTML à l’interieur d’un élément (au début
ou à la fin).
exemples/dom/ex02_basicAllSelector.html
1 <! doctype html>
2 <html l a n g=” f r ”>
3 <head>
4 <meta c h a r s e t=” u t f −8”>
5 <t i t l e>C o l l e c t i o n de t o u s l e s é l é ments</ t i t l e>
6 <s c r i p t s r c=” . / j q u e r y − 1 . 1 0 . 2 . j s ”></s c r i p t>
7 <s tyl e>
8 d i v#j a v a s c r i p t O u t p u t D i v {
9 background−color : #ddd ;
10 padding : 5px 0 ;
11 }
12 </s tyl e>
13 </head>
14

139
Rémy Malgouyres, http://malgouyres.org Programmation Web Côté Client, JS et jQuery

15 <body>
16 <h1>C o l l e c t i o n de t o u s l e s é l é ments</h1>
17 <div>
18 <h2>P a r t i e 1</h2>
19 <p>C e c i e s t l e t e x t e de l a p a r t i e 1 .</p>
20 </div>
21 <div>
22 <h2>P a r t i e 2</h2>
23 <p>Le t e x t e de l a p a r t i e 2 e s t d i f f é r e n t .</p>
24 </div>
25 <div i d=” j a v a s c r i p t O u t p u t D i v ”></div>
26 <s c r i p t>
27 // Ré cup é r a t i o n d ’ un e n s e m b l e d ’ é l é ments jQuery
28 var e l e m e n t s = $ ( ” *” ) ;
29 // O b t e n t i o n d ’ un Array d ’ Elements ( I n t e r f a c e du DOM W3C c l a s s i q u e )
30 var a r r a y E l e m e n t s = e l e m e n t s . toArray ( ) ;
31 // Parcours du t a b l e a u
32 f or ( var i =0 ; i<a r r a y E l e m e n t s . l e n g t h ; i ++){
33 // Ajout du nom du t a g HTML dans l e d i v d ’ ID j a v a s c r i p t O u t p u t D i v
34 $ ( ”#j a v a s c r i p t O u t p u t D i v ” ) . append ( a r r a y E l e m e n t s [ i ] . nodeName+” , ” ) ;
35 }
36 // Ajout d ’ un t i t r e AU DÉBUT du d i v d ’ ID j a v a s c r i p t O u t p u t D i v
37 $ ( ”#j a v a s c r i p t O u t p u t D i v ” ) . prepend ( ”<h2>L i s t e d e s é l é ments t r o u v é s</h2>” ) ;
38 </s c r i p t>
39 </body>

L’exemple suivant montre commen sélectionner certains éléments du document, par nom
de balise, classe CSS, etc. On apprend aussi à modifier des propriétés CSS des éléments.
exemples/dom/ex03_basicMultiSelector.html
1 <! doctype html>
2 <html l a n g=” f r ”>
3 <head>
4 <meta c h a r s e t=” u t f −8”>
5 <t i t l e>M o d i f i e r l e s t y l e de c e r t a i n s é l é ments</ t i t l e>
6 <s c r i p t s r c=” . / j q u e r y − 1 . 1 0 . 2 . j s ”></s c r i p t>
7 <s tyl e>

140
Chapitre D : Document Object Model (DOM)

8 p . myClass {
9 background−color : #ddd ;
10 padding : 10 px ;
11 }
12 </s tyl e>
13 </head>
14
15 <body>
16 <h1>M o d i f i e r l e s t y l e de c e r t a i n s é l é ments</h1>
17 <div>
18 <h2>P a r t i e 1</h2>
19 <p>C e c i e s t l e t e x t e de l a p a r t i e 1 .</p>
20 </div>
21 <div>
22 <h2>P a r t i e 2</h2>
23 <p c l a s s=” myClass ”>Le t e x t e de l a p a r t i e 2 e s t d i f f é r e n t .</p>
24 </div>
25 <s c r i p t>
26 // Ré cup é r a t i o n d ’ é l é ments jQuery pour l e s b a l i s e s <p> e t <h2>
27 var e l e m e n t s = $ ( ”p , h2 ” ) ;
28 e l e m e n t s . c s s ( ”border” , ”2 px s o l i d ” ) ;
29 // M o d i f i c a t i o n du s t y l e du t i t r e <h1>
30 $ ( ” h1 ” ) . c s s ( ” text −align ” , ” c e n t e r ” ) ;
31 // M o d i f i c a t i o n du s t y l e du ( ou d e s ) p a r a g r a p h e ( s ) de l a c l a s s e CSS myClass
32 $ ( ”p . myClass ” ) . c s s ( ”border−r a d i u s ” , ” 20 px ” ) ;
33 </s c r i p t>
34 </body>

D.2.2 Filtrage par le texte


L’exemple suivant montre comment sélectionner des éléments par mots du texte (sensible à la
casse).

exemples/dom/ex04_contains.html
1 <! doctype html>
2 <html l a n g=” f r ”>

141
Rémy Malgouyres, http://malgouyres.org Programmation Web Côté Client, JS et jQuery

3 <head>
4 <meta c h a r s e t=” u t f −8”>
5 <t i t l e>F i l t r a g e du t e x t e</ t i t l e>
6 <s c r i p t s r c=” . / j q u e r y − 1 . 1 0 . 2 . j s ”></s c r i p t>
7 <s tyl e>
8 p {
9 padding : 10 px 0 ;
10 }
11 </s tyl e>
12 </head>
13 <body>
14 <h1>F i l t r a g e du t e x t e</h1>
15 <div>
16 <h2>P a r t i e 1</h2>
17 <p>C e c i e s t l e t e x t e de l a p a r t i e 1 .</p>
18 </div>
19 <div>
20 <h2>P a r t i e 2</h2>
21 <p>Le t e x t e de l a <em>p a r t i e 2</em> e s t d i f f é r e n t .</p>
22 </div>
23 <s c r i p t>
24 $ ( ” p :c o n t a i n s ( ’ d i f f é r e n t ’ ) ” ) . prepend ( ’<s trong>Ce par ag r ap he c o n t i e n t l e mot
” d i f f é r e n t ”</s trong>.<br /> ’ ) . c s s ( ”background−color ” , ”#ddd ” ) ;
25 </s c r i p t>
26 </body>

D.2.3 Application de Méthode aux éléments


L’exemple suivant montre comment appliquer une fonction à chacun des éléments sélectionnés.
Ici, on met le contenu des paragraphes en gras. On ajoute une information au début de chaque
paragraphe de la classe myClass.

exemples/dom/ex05_each.html
1 <! doctype html>
2 <html l a n g=” f r ”>

142
Chapitre D : Document Object Model (DOM)

3 <head>
4 <meta c h a r s e t=” u t f −8”>
5 <t i t l e>A p p l i q u e r une mé thode à chaque é l é ment</ t i t l e>
6 <s c r i p t s r c=” . / j q u e r y − 1 . 1 0 . 2 . j s ”></s c r i p t>
7 <s tyl e>
8 p . myClass {
9 background−color : #ddd ;
10 padding : 10 px ;
11 }
12 </s tyl e>
13 </head>
14
15 <body>
16 <h1>A p p l i q u e r une mé thode à chaque é l é ment</h1>
17 <div>
18 <h2>P a r t i e 1</h2>
19 <p>C e c i e s t l e t e x t e de l a p a r t i e 1 .</p>
20 </div>
21 <div>
22 <h2>P a r t i e 2</h2>
23 <p c l a s s=” myClass ”>Le t e x t e de l a p a r t i e 2 e s t d i f f é r e n t .</p>
24 </div>
25 <s c r i p t>
26 $ ( ” p” ) . each ( function ( ) {
27 $ ( t h i s ) . c s s ( ” font−weight” , ” b o l d e r ” ) ;
28 i f ( $ ( t h i s ) . h a s C l a s s ( ” myClass ” ) ) {
29 $ ( t h i s ) . prepend ( ”<em>p a r a g r a p h e de c l a s s e myClass</em><br />” ) ;
30 }
31 }) ;
32 </s c r i p t>
33 </body>

143
Rémy Malgouyres, http://malgouyres.org Programmation Web Côté Client, JS et jQuery

D.2.4 Événements et Callbacks


EL’exemple suivant montre comment, en réaction au click sur un bouton, transformer es pa-
ragraphes en div.

exemples/dom/ex06_clickEvent.html
1 <! doctype html>
2 <html l a n g=” f r ”>
3 <head>
4 <meta c h a r s e t=” u t f −8”>
5 <t i t l e>Év é nement de c l i c k</ t i t l e>
6 <s c r i p t s r c=” . / j q u e r y − 1 . 1 0 . 2 . j s ”></s c r i p t>
7 <s tyl e>
8 p {
9 background−color : #ddd ;
10 padding : 10 px ;
11 }
12 d i v . myClass {
13 font−weight : b o l d e r ;
14 padding : 10 px ;
15 border −style : dashed ;
16 }
17 em {
18 font −variant : s m a l l −c a p s ;
19 font−s i z e : 120% ;
20 }
21 button {
22 margin : 10 px 0 ;
23 }
24 </s tyl e>
25 </head>
26
27 <body>
28 <h1>Év é nement de c l i c k</h1>
29 <div>

144
Chapitre D : Document Object Model (DOM)

30 <h2>P a r t i e 1</h2>
31 <p>C e c i e s t l e t e x t e de l a p a r t i e 1 .</p>
32 </div>
33 <div>
34 <h2>P a r t i e 2</h2>
35 <p>Le t e x t e de l a <em>p a r t i e 2</em> e s t d i f f é r e n t .</p>
36 </div>
37 <button>M o d i f i e r l e s p a r a g r a p h e s</button>
38 <s c r i p t>
39 // Év é nement de c l i c k
40 $ ( ” b u t t o n ” ) . c l i c k ( function ( ) {
41 // A p p l i c a t i o n d ’ une mé t h o d e à chaque p a r a g r a p h e
42 $ ( ”p” ) . each ( function ( ) {
43 // Remplacer l e <p> par un <div> en l a i s s a n t l e HTML i n c h a n g é
44 $ ( t h i s ) . r e p l a c e W i t h ( ’<div c l a s s=” myClass ”> ’ + $ ( t h i s ) . html ( )
+ ”</div>” ) ;
45 }) ;
46 }) ;
47 </s c r i p t>
48 </body>

D.2.5 Fitrage d’un Tableau


L’exemple suivant montre comment, en utilisant les utilitaires de jQuery permettant de traiter
des Array Javascript génériques :

1. Filtrer le contenu d’un tableau avec une méthode de choix booléenne pour les éléments
(ici, valeur multiple de 3) ;

2. Générer le HTML en appliquant une méthode à chaque élément du tableau.

145
Rémy Malgouyres, http://malgouyres.org Programmation Web Côté Client, JS et jQuery

exemples/dom/ex07_filterGrep.html
1 <! doctype HTML>
2 <html l a n g=” f r ”>
3 <head>
4 <meta c h a r s e t=”UTF−8” />
5 <t i t l e>F i l t r a g e Grep s u r Tableau</ t i t l e>
6 </head>
7 <body>
8 <h1>F i l t r a g e Grep s u r Tableau</h1>
9 <s c r i p t s r c=” . / j q u e r y − 1 . 1 0 . 2 . j s ”></s c r i p t>
10
11 <p i d=” o u t p u t ”><p>
12
13 <s c r i p t>
14 // Cré a t i o n d ’ un t a b l e a u a v e c l e s e n t i e r s de 0 à 19
15 var tab = new Array ( ) ;
16 f or ( var i =0 ; i<20 ; i ++){
17 tab . push ( i ) ;
18 }
19
20 // Sé l e c t i o n d e s é l é ments du t a b l e a u par l a f o n c t i o n ” m u l t i p l e de 3”
21 var t a b M u l t i p l e D e 3 = $ . g r e p ( tab , function ( key , v a l u e ) {
22 i f ( key%3 == 0 )
23 return true ;
24 else
25 return f a l s e ;
26 }) ;
27
28 // A f f i c h a g e du t a b l e a u d e s m u l t i p l e s de 3
29 var outHTML = ” ” ;
30 // A p p l i c a t i o n d ’ une f o n c t i o n ( g éné r a t i o n d ’HTML)
31 // à chaque é l é ment du t a b l e a u
32 $ . each ( tabMultipleDe3 , function ( key , v a l u e ) {
33 outHTML += ” t a b [ ”+key +” ] = ”+v a l u e+”<br />” ;
34 }) ;
35 $ ( ”#o u t p u t ” ) . append ( outHTML ) ;
36 </s c r i p t>
37 </body>
38 </html>

146

Vous aimerez peut-être aussi