Académique Documents
Professionnel Documents
Culture Documents
Programmation Web Javascript
Programmation Web Javascript
Programmation, Conception
et Design Patterns en JavaScript ;
Web Côté Client avec jQuery
Rémy Malgouyres
LIMOS UMR 6158, IUT, département info
Université Clermont Auvergne
B.P. 86
63172 AUBIERE cedex
https://malgouyres.org/
https://malgouyres.org/programmation-html-css
https://malgouyres.org/tutoriel-drupal
https://malgouyres.org/programmation-php
https://malgouyres.org/programmation-javascript
Cours sur l’administration de serveurs (Serveurs WEB avec apache, SSL, LDAP...) :
https://malgouyres.org/administration-reseau
Table des matières
1
TABLE DES MATIÈRES
2
TABLE DES MATIÈRES
3
Architectures client/serveur et API
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)).
do
ée
requêtes
données
re
es
nn
nn
qu
êt
do
ée
qu
êt
s
es
re
On aura dans la mesure du possible intérêt à limiter le plus possible le travail côté client
pour les raisons suivantes :
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.
4
TABLE DES MATIÈRES
• 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.
5
Chapitre 1
6
Chapitre 1 : Premiers pas en JavaScript
Dans ce dernier cas, on ne peut pas générer de code directement dans le document HTML
(avec document.write) 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).
La fonction alert peut par exemple utilisé pour du débuggage si l’on ne dispose pas d’un
outil de debug intégré dans notre IDE.
7
Rémy Malgouyres, https://malgouyres.org Programmation JavaScript, Patterns, Web
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.
Code Source 1.6 : /bases-js/ex03-functionTest.html
1 <!doctype HTML>
2 <html lang=” f r ”>
3 <head>
4 <meta charset=”UTF−8” />
8
Chapitre 1 : Premiers pas en JavaScript
Notons que l’on peut aussi déclarer une fonction un peu comme en PHP de la manière
suivante :
mais la fonction est alors globale (son nom existe dans tout le programme).
9
Rémy Malgouyres, https://malgouyres.org Programmation JavaScript, Patterns, Web
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).
• 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.
10
Chapitre 1 : Premiers pas en JavaScript
1.4.2 Méthodes
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.
11
Rémy Malgouyres, https://malgouyres.org Programmation JavaScript, Patterns, Web
16 // F on ct i o n dans l e c o n t e x t e g l o b a l :
17 /* * @ d e s c r i p t i o n Gé nère l e code HTML pour a f f i c h e r un o b j e t q u e l c o n q u e
18 * @function getHtmlObjet
19 * @param { O b j e c t } o b j e t − L ’ o b j e t à t r a i t e r
20 * @return Le code HTML pour a f f i c h e r l ’ o b j e t
21 */
22 var getHtmlObjet = function ( o b j e t ) {
23 var c h a i n e = ” ” ;
24 // 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 ” ) :
25 fo r ( var nom in o b j e t ) {
26 c h a i n e += ” o b j e t [ \ ” ”+nom+” \ ” ] = ”
27 + o b j e t [ nom ] // Appel de l a mé t h o d e t o S t r i n g par d é f a u t
28 +”<br />” ;
29 }
30 return c h a i n e ;
31 } ;
32
33 // 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 :
34 var codeHTML = ”<p>” + getHtmlObjet ( p r o d u i t ) + ”</p>” ;
35 // a p p e l d ’ une mé t h o d e :
36 codeHTML += ”<p>P r i x TTC : ” + p r o d u i t . getPrixTTC ( ) + ”</p>” ;
37 // Mise à j o u r de l a vue
38 document . getElementById ( ” p a r a g r a p h e R e s u l t a t ” ) . innerHTML = codeHTML ;
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.
12
Chapitre 1 : Premiers pas en JavaScript
9 memory : ” 4GB” ,
10 ” p r i x s u p p l é m e n t a i r e HT” : 5 0 . 0 ,
11 /* * @ d e s c r i p t i o n Gé nère l e code HTML d e s o p t i o n s
12 * @method getHTML
13 */
14 getHtml : function ( ) {
15 return t h i s . p r o c e s s o r + ” ” + t h i s . memory +
16 ” ( 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 ; ) ” ;
17 }
18 },
19 /* * @ d e s c r i p t i o n Gé nère l e code HTML c o m p l e t du p r o d u i t
20 * @method getHTML
21 */
22 getHtml : function ( ) {
23 return t h i s . denomination +
24 ”<br />p r i x TTC t o u t compris : ”
25 + ( 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 )
)
26 *(1.0+ t h i s . tauxTVA / 1 0 0 . 0 )
27 + ” &euro ;<br />” + t h i s . o p t i o n s . getHtml ( ) + ”<br />” ;
28 }
29 };
30
31 // a p p e l d ’ une mé t h o d e :
32 var codeHTML = ”<p>” + p r o d u i t . getHtml ( ) + ”</p>” ;
33 // Mise à j o u r de l a vue
34 document . getElementById ( ” p a r a g r a p h e R e s u l t a t ” ) . innerHTML = codeHTML ;
On peut aussi choisir de définir l’objet contenant les options dans une méthode getOptions
du composite, qui retourne un objet. La méthode getOptions joue alors un rôle de “fabrique”.
13
Rémy Malgouyres, https://malgouyres.org Programmation JavaScript, Patterns, Web
25 */
26 getHtml : function ( ) {
27 return t h i s . denomination +
28 ”<br />p r i x TTC t o u t compris : ”
29 + ( t h i s . prixHT_base
30 + ( t h i s . g e t 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 ) )
31 *(1.0+ t h i s . tauxTVA / 1 0 0 . 0 )
32 + ” &euro ;<br />” + t h i s . g e t O p t i o n s ( ) . getHtml ( ) + ”<br />” ;
33 }
34 };
35
36 // a p p e l d ’ une mé t h o d e :
37 var codeHTML = ”<p>” + p r o d u i t . getHtml ( ) + ”</p>” ;
38 // Mise à j o u r de l a vue
39 document . getElementById ( ” p a r a g r a p h e R e s u l t a t ” ) . innerHTML = codeHTML ;
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.
14
Chapitre 1 : Premiers pas en JavaScript
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
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.
Code Source 1.15 : /bases-js/ex09-arraysNew.js
1 /* * @ d e s c r i p t i o n Dé c l a r a t i o n d ’ un Array s o u s forme de l i t t é r a l */
2 var tab = new Array ( 1 , 3 , ” coucou ” , 6 ) ;
3 tab [ 4 ] = 9 ; // Ajout d ’ un é l é ment
4 // Géné r a t i o n dynamique de code HTML :
5 var codeHTML = ”Donné e s du t a b l e a u :<br />” ;
6 // Parcours du t a b l e a u a v e c un i n d i c e numé r i q u e
7 for ( var i =0 ; i<tab . l e n g t h ; i ++){
8 i f ( i > 0) {
9 codeHTML += ” , ”
10 }
15
Rémy Malgouyres, https://malgouyres.org Programmation JavaScript, Patterns, Web
11 codeHTML += tab [ i ] ;
12 }
13 // Mise à j o u r de l a vue
14 document . getElementById ( ” p a r a g r a p h e R e s u l t a t ” ) . innerHTML = codeHTML ;
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.
16
Chapitre 1 : Premiers pas en JavaScript
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).
– 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).
17
Rémy Malgouyres, https://malgouyres.org Programmation JavaScript, Patterns, Web
18
Chapitre 1 : Premiers pas en JavaScript
19
Chapitre 2
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.
20
Chapitre 2 : Programmation Fonctionnelle et Objet en JavaScript
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.
21
Rémy Malgouyres, https://malgouyres.org Programmation JavaScript, Patterns, Web
est passé en premier argument lors de l’invocation. Les arguments ordinaires de la méthode,
suivant la définition de ses paramètres, sont transmis, lors de l’invocation, dans un Array passé
en second argument.
22
Chapitre 2 : Programmation Fonctionnelle et Objet en JavaScript
35 } ;
36
37 // I n v o c a t i o n c l a s s i q u e de l a mé t h o d e a f f i c h a n t l e p r o d u i t :
38 codeHTML = p r o d u i t . getHtml ( ” I n v o c a t i o n Normale ” , ” span ” ) ;
39 // I n v o c a t i o n a v e c p a t t e r n a p p l y de l a mé t h o d e de ” p r o d u i t ”
40 // pour a f f i c h e r ” b l o c k b u s t e r ” :
41 codeHTML += p r o d u i t . getHtml . apply ( b l o c k b u s t e r , // O b j e t p r e n a n t p l a c e de t h i s
42 // L i s t e d e s arguments de l a mé t h o d e :
43 [ ” I n v o c a t i o n \” a p p l y \” s u r b l o c k b u s t e r ” , // t i t r e
44 ” span ” ] ) ; // b a l i s e
45 // Mise à j o u r de l a vue
46 document . getElementById ( ” p a r a g r a p h e R e s u l t a t ” ) . innerHTML = codeHTML ;
23
Rémy Malgouyres, https://malgouyres.org Programmation JavaScript, Patterns, Web
24
Chapitre 2 : Programmation Fonctionnelle et Objet en JavaScript
Même si l’exécution peut éventuellement fonctionner sur certain compilateurs, le code n’est
pas défini dans le standard du C ANSI, et le comportement peut donner n’importe quoi ! On
peut mettre en évidence le bug avec l’outil valgrind, qui détecte une erreur mémoire (ici sur la
ligne 13) :
25
Rémy Malgouyres, https://malgouyres.org Programmation JavaScript, Patterns, Web
10 return a c c e s V a r i a b l e X ; // On r e t o u r n e l a f o n c t i o n l o c a l e
11 } ;
12
13 var getX = maFonction ( ) ; // On r é c u p è r e l a f o n c t i o n r e t o u r n é e par maFonction
14 codeHTML = ”La v a r i a b l e l o c a l e x a pour v a l e u r ” + getX ( ) ;
15 document . getElementById ( ” p a r a g r a p h e R e s u l t a t ” ) . innerHTML = codeHTML ;
26
Chapitre 2 : Programmation Fonctionnelle et Objet en JavaScript
Le fichier suivant teste les accès aux données et méthodes publiques du module suivant le
pattern module :
27
Rémy Malgouyres, https://malgouyres.org Programmation JavaScript, Patterns, Web
2 var s e c r e t M o d u l e = mySecretModule ( ” i n i t S e c r e t ” ) ;
3 // Code HTML à a j o u t e r au p a r a g r a p h e d ’ ID p a r a g r a p h e R e s u l t a t
4 var codeHTML = ” ” ;
5 // Accès à l a donn é e p u b l i q u e de l ’ i n t e r f a c e :
6 codeHTML += ” 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 />” ;
7 // 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 de l ’ i n t e r f a c e :
8 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 ” ;
9 codeHTML += ” 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 />” ;
10
11 // A c c e s s e u r de s e c r e t ( v a r i a b l e l o c a l e p r i v é e du ” p a t t e r n module ” ) :
12 codeHTML += ” 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 />” ;
13 // 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 ( l e s e t t e r p u b l i c f a i t d e s t e s t s ) :
14 try {
15 s e c r e t M o d u l e . s e t S e c r e t ( ” abcde ” ) ; // La cha î ne n ’ e n t r a î ne pas d ’ e r r e u r
16 codeHTML += ” 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 />” ;
17 } catch ( e ) {
18 codeHTML += ” Erreur de t y p e ” + e . name + ”<br />Message : ” + e . message + ”<br /
>” ;
19 }
20 // 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 ( l e s e t t e r p u b l i c f a i t d e s t e s t s ) :
21 try {
22 s e c r e t M o d u l e . s e t S e c r e t ( ” abcde567 ” ) ; // La cha î ne g é nère une e r r e u r
23 codeHTML += ” 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 />” ;
24 } catch ( e ) {
25 codeHTML += ” Erreur de t y p e ” + e . name + ” : ” + e . message + ”<br />” ;
26 }
27 document . getElementById ( ” p a r a g r a p h e R e s u l t a t ” ) . innerHTML = codeHTML ;
Le 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...
28
Chapitre 2 : Programmation Fonctionnelle et Objet en JavaScript
15 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 ) {
16 // 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
17 var a d r e s s e = {} ;
18 // L i s t e d e s ” a t t r i b u t s ” d ’ une a d r e s s e ( p r o p r i é t é s a t t e n d u e s )
19 var l i s t e P r o p r i e t e s = [ ” i d ” , ”numeroRue” , ” rue ” , ” complementAddr ” ,
20 ” c o d e P o s t a l ” , ” v i l l e ” , ” pays ” ] ;
21 // 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
22 fo r ( propertyName in s p e c ) {
23 i f ( s p e c . hasOwnProperty ( propertyName ) ) {
24 // 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 :
25 i f ( l i s t e P r o p r i e t e s . indexOf ( propertyName ) >= 0 ) {
26 a d r e s s e [ propertyName ] = s p e c [ propertyName ] ;
27 } else {
28 throw {
29 name : ” UnknownPropertyException ” ,
30 message : ” P r o p r i é t é de l ’ a d r e s s e inconnue . ”
31 };
32 } Les
33 }
34 }
35 return a d r e s s e ;
36 };
• Une méthode addModule qui permet d’ajouter un objet quelconque (de type pattern-fonct,
Function, Array, etc.) sous la forme de propriété de l’application.
29
Rémy Malgouyres, https://malgouyres.org Programmation JavaScript, Patterns, Web
• 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.
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”,
30
Chapitre 2 : Programmation Fonctionnelle et Objet en JavaScript
”
Code Source 2.13 : Fichiers JS inclus dans ex04-structureApplicationTest.html
1 <p id=” p a r a g r a p h e R e s u l t a t ”></p>
2 <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>
3 <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 T e s t . j s ”></s c r i p t>
31
Rémy Malgouyres, https://malgouyres.org Programmation JavaScript, Patterns, Web
• 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
expressions régulière sur une chaîne, avec éventuellement des conditions de longueur minimale
ou maximale sur la chaîne (exemple : champs obligatoire...).
32
Chapitre 2 : Programmation Fonctionnelle et Objet en JavaScript
42 * 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
43 * e t un message d ’ e r r e u r en c a s d ’ é c h e c
44 * @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
45 * @param {number} [ s p e c . minLength =0] − l o n g u e u r minimale pour l a cha î ne
46 * @param {number} [ s p e c . maxLength=u n d e f i n e d ] − l o n g u e u r maximale pour l a
cha î ne
47 * @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 t i o n s s o n t s a t i s f a i t e s ,
48 * un message d ’ e r r e u r pour un u t i l i s a t e u r 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 === u n d e f i n e d | |
54 s p e c . c h a i n e . l e n g t h <= s p e c . maxLength )
55 ){
56 return s p e c . r e g e x . t e s t ( s p e c . c h a i n e ) ;
57 }
58 return ” Erreur : l o n g u e u r de l ’ e n t r é e ( champ o b l i g a t o i r e , t r o p l o n g . . . ) ” ;
59 };
60
61 /* * @ d e s c r i p t i o n I n t e r f a c e p u b l i q u e du ” p a t t e r n module ” pour r e g e x U t i l s ,
62 * r e t o u r n é par l a f o n c t i o n , c o n t i e n t l e s mé t h o d e s p u b l i q u e s du module . */
63 var p u b l i c I n t e r f a c e R e g e x = {
64 /* * @ d e s c r i p t i o n t e s t e l ’ e x p r e s s i o n du l a n g a g e n a t u r e l a v e c e s p a c e s
65 * @method t e s t R e g e x L a t i n 1
66 * @public
67 * @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
68 * @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
69 * @param {number} [ s p e c . minLength =0] − l o n g u e u r minimale de l a cha î ne
70 * @param {number} [ s p e c . maxLength=u n d e f i n e d ] − l o n g u e u r max de l a cha î ne
71 * @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 t i o n s s o n t s a t i s f a i t e s ,
72 * un message d ’ e r r e u r pour un u t i l i s a t e u r s i n o n .
73 */
74 t e s t R e g e x L a t i n 1 : function ( s p e c ) {
75 // Ajout d ’ une p r o p r i é t é à s p e c ( a ug me n ta t i on )
76 spec . regex = regexLatin1 ;
77 return v a l i d a t e R e g e x ( s p e c ) ;
78 },
79
80 /* * @ d e s c r i p t i o n t e s t e l ’ e x p r e s s i o n du l a n g a g e n a t u r e l , e s p a c e s , c h i f f r e s
81 * @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
82 * @public
83 * @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
84 * @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
85 * @param {number} [ s p e c . minLength =0] − l o n g u e u r minimale de l a cha î ne
86 * @param {number} [ s p e c . maxLength=u n d e f i n e d ] − l o n g u e u r max de l a cha î ne
87 * @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 t i o n s s o n t s a t i s f a i t e s ,
88 * un message d ’ e r r e u r pour un u t i l i s a t e u r s i n o n .
89 */
90 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 ) {
91 // Ajout d ’ une p r o p r i é t é à s p e c ( a ug me n ta t i on )
92 spec . regex = regexLatin1WithDigits ;
93 return v a l i d a t e R e g e x ( s p e c ) ;
94 },
95
96 /* * @ d e s c r i p t i o n t e s t e l e l a n g a g e n a t u r e l , e s p a c e s , c h i f f r e s e t
33
Rémy Malgouyres, https://malgouyres.org Programmation JavaScript, Patterns, Web
ponctuation
97 * @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
98 * @public
99 * @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
100 * @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
101 * @param {number} [ s p e c . minLength =0] − l o n g u e u r minimale de l a cha î ne
102 * @param {number} [ s p e c . maxLength=u n d e f i n e d ] − l o n g u e u r max de l a cha î ne
103 * @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 t i o n s s o n t s a t i s f a i t e s ,
104 * un message d ’ e r r e u r pour un u t i l i s a t e u r s i n o n .
105 */
106 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 ) {
107 // Ajout d ’ une p r o p r i é t é à s p e c ( a ug me n ta t i on )
108 spec . regex = regexLatin1WithDigitsPunctuation ;
109 return v a l i d a t e R e g e x ( s p e c ) ;
110 }
111 } ; // f i n du l i t t é r a l d é f i n i s s a n t p u b l i c I n t e r f a c e R e g e x
112
113 // 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 ( p a t t e r n ” module ” ) .
114 return p u b l i c I n t e r f a c e R e g e x ;
115
116 } ( ) ] // 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 ”
117 ) ; // f i n de l ’ a p p e l de l a mé t h o d e myApp . addModule a v e c l e p a t t e r n ” a p p l y ”
118 // ( 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 t i 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.
34
Chapitre 2 : Programmation Fonctionnelle et Objet en JavaScript
• Un module métier permet de représenter des entités relevant du métier qui possèdent
(regroupent) des attributs.
Exemple. Un module métier myApp.metier.adresse regroupera les attributs id, numeroRue,
rue, complementAddr, codePostal, ville et pays...
• Chaque module métier comprendra des méthodes d’instances, qui s’appliqueront aux
instances, et dont l’implémentation s’appuiera sur les valeurs des attributs.
Exemple. La méthode d’instance getAttribute, appelée accesseur, permet d’obtenir la
valeur d’un attribut dans une instance à partir du nom de l’attribut.
• Chaque module métier comprendra des méthodes de classe, dont l’implémentation et le
résultat seront indépendant des valeurs des attributs, donc indépendante des instances.
Exemple. La méthode de classe getAttributeList renvoie, sous forme d’Array, la liste
des noms d’attributs du module métier (liste commune à toutes les instances d’un même
module métier).
35
Rémy Malgouyres, https://malgouyres.org Programmation JavaScript, Patterns, Web
Chaque module métier est construit à partir d’un objet attributesPatterns, qui définit
la structure d’une instance. Ici, attributesPatterns définit, pour chaque attribut, une mé-
thode de test par expression régulière de validité d’une valeur pour l’attribut, et une propriété
labelText à afficher pour indiquer à l’utilisateur de quelle donnée il s’agit (typiquement : texte
de l’élément HTML <label> associé à un input dans un formulaire). On pourrait facilement
adapter le code pour permettre des propriétés calculées, ou encore différents types d’éléments
d’interface utilisateur (divers inputs (couleur, nombre, date,...), de textarea ou de select) dans
les formulaires, etc.
36
Chapitre 2 : Programmation Fonctionnelle et Objet en JavaScript
34 // q u i c o r r e s p o n d e n t aux a t t r i b u t s de l ’ i n s t a n c e
35 fo r ( var attributeName in a t t r i b u t e s P a t t e r n s ) {
36 // 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 .
37 i f ( a t t r i b u t e s P a t t e r n s . hasOwnProperty ( attributeName ) ) {
38 l i s t e . push ( attributeName ) ;
39 }
40 }
41
42 return l i s t e ;
43 } ( ) ; // a p p e l immé d i a t de l a f o n c t i o n anonyme .
44
45
46 // //////////////////////////////////////////////
47 // I n t e r f a c e p u b l i q u e du module
48
49 /* * @ d e s c r i p t i o n 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
50 * ( 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 ” ) .
51 */
52 var p u b l i c I n t e r f a c e M o d u l e s M e t i e r = {
53
54 /* * @ d e s c r i p t i o n Renvoie l a l i s t e d e s noms d ’ a t t r i b u t s s d e s i n s t a n c e s .
55 * @method g e t A t t r i b u t e L i s t
56 */
57 g e t A t t r i b u t e L i s t : function ( ) {
58 return a t t r i b u t e L i s t ;
59 },
60
61 /* * @ d e s c r i p t i o n Renvoie l e t e x t e de d e s c r i p t i o n d ’ un a t t r i b u t d e s i n s t a n c e s
.
62 * @method g e t L a b e l T e x t
63 * @param { s t r i n g } a t t r i b u t e N a m e − nom de p r o p r i é t é
64 * @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
65 */
66 g e t L a b e l T e x t : function ( attributeName ) {
67 return a t t r i b u t e s P a t t e r n s [ attributeName ] . l a b e l T e x t ;
68 },
69
70 /* * @ d e s c r i p t i o n 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 a t t r i b u t s
71 * des i n s t a n c e s .
72 * 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 .
73 * @method t e s t R e g e x
74 * @param { s t r i n g } a t t r i b u t e N a m e − nom de p r o p r i é t é
75 * @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 t t r i b u t
76 * @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 ,
77 * 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 : function ( attributeName , v a l u e ) {
80 i f ( a t t r i b u t e s P a t t e r n s [ attributeName ] === u n d e f i n e d ) {
81 return ”La p r o p r i é t é ” + attributeName + ” n ’ e x i s t e pas ” ;
82 } else {
83 return a t t r i b u t e s P a t t e r n s [ attributeName ] . r e g e x T e s t ( v a l u e ) ;
84 }
85 }
86
87 } ; // 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 M o d u l e s M e t i e r
88
37
Rémy Malgouyres, https://malgouyres.org Programmation JavaScript, Patterns, Web
89 myApp . m e t i e r [ moduleName ] = p u b l i c I n t e r f a c e M o d u l e s M e t i e r ;
90
91 } ] // f i n de l a f o n c t i o n q u i c r é e l ’ o b j e t myApp . m e t i e r [ moduleName ]
92
93 ) ; // 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
94 // ( 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 M o d u l e s M e t i e r au m e t i e r , s o u s l e nom
createModuleMetier )
38
Chapitre 2 : Programmation Fonctionnelle et Objet en JavaScript
39 chaine : chaine ,
40 maxLength : 15
41 } ) === true )
42 {
43 return true ;
44 } else {
45 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 , ”
46 +” 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 . ” ;
47 }
48 },
49 l a b e l T e x t : ”Numé ro ”
50 },
51 rue : {
52 r e g e x T e s t : function ( c h a i n e ) {
53 i f (myApp . m e t i e r . 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 ( {
54 chaine : chaine ,
55 minLength : 1 ,
56 maxLength : 255
57 } ) === true )
58 {
59 return true ;
60 } else {
61 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 ”
62 + ” 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 . ” ;
63 }
64 },
65 l a b e l T e x t : ” rue / p l a c e ”
66 },
67 complementAddr : {
68 r e g e x T e s t : function ( c h a i n e ) {
69 i f (myApp . m e t i e r . 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 ( {
70 chaine : chaine ,
71 maxLength : 255
72 } ) === true )
73 {
74 return true ;
75 } else {
76 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 , ”
77 + ” 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 . ” ;
78 }
79 },
80 l a b e l T e x t : ” Lieu d i t , Bâ timent , BP”
81 },
82 codePostal : {
83 r e g e x T e s t : function ( c h a i n e ) {
84 i f ( /^ [0 −9]{5} $/ . t e s t ( c h a i n e ) === true ) {
85 return true ;
86 } else {
87 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 . ” ;
88 }
89 },
90 l a b e l T e x t : ”Code P o s t a l ”
91 },
92 ville : {
93 r e g e x T e s t : function ( c h a i n e ) {
94 i f (myApp . m e t i e r . r e g e x U t i l . t e s t R e g e x L a t i n 1 ( {
39
Rémy Malgouyres, https://malgouyres.org Programmation JavaScript, Patterns, Web
95 chaine : chaine ,
96 minLength : 1 ,
97 maxLength : 255
98 } ) === true )
99 {
100 return true ;
101 } else {
102 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 , ”
103 + ” t i r e t s et guillemets . ” ;
104 }
105 },
106 labelText : ” Ville ”
107 },
108 pays : {
109 r e g e x T e s t : function ( c h a i n e ) {
110 i f (myApp . m e t i e r . r e g e x U t i l . t e s t R e g e x L a t i n 1 ( {
111 chaine : chaine ,
112 minLength : 1 ,
113 maxLength : 255
114 } ) === true )
115 {
116 return true ;
117 } else {
118 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 , ”
119 + ” t i r e t s et guillemets . ” ;
120 }
121 },
122 l a b e l T e x t : ” Pays ”
123 }
124 } // f i n de l ’ o b j e t a t t r i b u t e s P a t t e r n s
125 ) ; // f i n de l ’ i n v o c a t i o n de myApp . m e t i e r . c r e a t e M o d u l e M e t i e r
• L’objet privé dataError contient comme propriétés les éventuels messages d’erreur suite
aux tests (typiquement d’expression régulière) sur la validité des valeurs des attributs de
l’instance d’objets métier ;
Des méthodes publiques, dans l’interface du module, permettent d’accéder à, ou de modifier
les données de l’instance. Notons que les méthodes de l’interface publique du module créé
40
Chapitre 2 : Programmation Fonctionnelle et Objet en JavaScript
peuvent utiliser les méthodes du module parent en utilisant le pattern that (voir la partie 2.1.3).
L’interface publique des instances expose aussi les méthodes statiques (méthodes de classes),
dont le code ne dépend pas des instances, mais est factorisé au niveau du module métier (ici
donné par l’objet that suivant le pattern that).
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.
41
Rémy Malgouyres, https://malgouyres.org Programmation JavaScript, Patterns, Web
39 // l ’ i n t e r f a c e p u b l i q u e d e s i n s t a n c e s ( p u b l i c I n t e r f a c e I n s t a n c e ) c i −d e s s o u s ,
40 // ” t h i s ” r é f é r e r a à c e t a u t r e o b j e t ( i c i p u b l i c I n t e r f a c e I n s t a n c e ) .
41 // Une s o l u t i o n c o n s i s t e à mé m o r i s e r l ’ o b j e t t h i s dans une v a r i a b l e t h a t ,
42 // e t d ’ a p p e l e r l a mé t h o d e t h a t . t e s t R e g e x e t non pas t h i s . t e s t R e g e x
43 // dans l a f o n c t i o n l o c a l e s e t A t t r i b u t e A n d E r r o r c i −d e s s o u s .
44 var t h a t = t h i s ; // exemple : t h i s = myApp . m e t i e r . a d r e s s e
45
46 /* * @ d e s c r i p t i o n A j o u t e un message d ’ e r r e u r a s s o c i é à un a t t r i b u t
47 * @method addError
48 * @private
49 */
50 var addError = function ( attributeName , message ) {
51 // Ajout d ’ une p r o p r i é t é
52 d a t a E r r o r [ attributeName ] = message ;
53 }
54
55 /* * @ d e s c r i p t i o n 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 un a t t r i b u t d ’ une i n s t a n c e .
56 * En c a s d ’ e r r e u r un message pour c e t a t t r i b u t e s t e s t a j o u t é dans d a t a E r r o r .
57 * 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 .
58 * @method i n p u t O b j .
59 * @private
60 */
61 var s e t A t t r i b u t e A n d E r r o r = function ( attributeName , v a l u e ) {
62 var r e s u l t T e s t R e g e x = t h a t . t e s t R e g e x ( attributeName , v a l u e ) ;
63 // On i n t i a l i s e l ’ a t t r i b u t de l ’ i n s t a n c e
64 d a t a A t t r i b u t e s [ attributeName ] = v a l u e ;
65 // 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
66 i f ( r e s u l t T e s t R e g e x === true ) {
67 // 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
68 delete d a t a E r r o r [ attributeName ] ;
69 } else {
70 // On i n i t a l i s e l ’ a t t r i b u t de l ’ o b j e t d e s e r r e u r s .
71 // a v e c l e message d ’ e r r e u r .
72 addError ( attributeName , ” A t t r i b u t ” + v a l u e +
73 ” i n v a l i d e : ” + resultTestRegex ) ;
74 }
75 }
76
77 // I n i t i a l i s a t i o n d e s a t t r i b u t s de l ’ i n s t a n c e .
78 // 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
79 i f ( inputObj !== null ) {
80 // Parcours d e s p r o p r i é t é s de g e t A t t r i b u t e L i s t ( )
81 // q u i c o r r e s p o n d e n t aux a t t r i b u t s de l ’ i n s t a n c e à c r é e r
82 f o r ( var i = 0 ; i < t h i s . g e t A t t r i b u t e L i s t ( ) . l e n g t h ; ++i ) {
83 var attributeName = t h i s . g e t A t t r i b u t e L i s t ( ) [ i ] ;
84 // U t i l i s a t i o n du s e t t e r pour i n i t i a l i s e r l ’ a t t r i b u t
85 s e t A t t r i b u t e A n d E r r o r ( attributeName , inputObj [ attributeName ] ) ;
86 }
87 } else {
88 // On i n i t i a l i s e l e s v a l e u r s d e s a t t r i b u t s à ””
89 f o r ( var i = 0 ; i < t h i s . g e t A t t r i b u t e L i s t ( ) . l e n g t h ; ++i ) {
90 var attributeName = t h i s . g e t A t t r i b u t e L i s t ( ) [ i ] ;
91 d a t a A t t r i b u t e s [ attributeName ] = ” ” ;
92 }
93 }
94
42
Chapitre 2 : Programmation Fonctionnelle et Objet en JavaScript
95 // //////////////////////////////////////////////
96 // I n t e r f a c e p u b l i q u e du module
97
98 /* * @ d e s c r i p t i o n I n t e r f a c e p u b l i q u e d e s i n s t a n c e s du module mé t i e r .
99 * F o u r n i t l e s mé t h o d e s pour m a n i p u l e r l ’ i n s t a n c e ( a c c e s s e u r s , s e t t e r s . . . )
100 */
101 var p u b l i c I n t e r f a c e I n s t a n c e = {
102 /* * @ d e s c r i p t i o n 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 ”
103 * (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 )
104 * @return { O b j e c t } l e module myApp . m e t i e r . moduleName
105 */
106 getModule : function ( ) {
107 return t h a t ;
108 },
109
110 /* * @ d e s c r i p t i o n 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 .
111 * @method g e t A t t r i b u t e
112 * @public
113 * @param { s t r i n g } a t t r i b u t e N a m e − nom de l ’ a t t r i b u t a t t e n d u e d ’ une
instance
114 * @return { s t r i n g } l a v a l e u r de l ’ a t t r i b u t ou u n d e f i n e d en c a s de nom d ’
a t t r i b u t inconnu .
115 */
116 g e t A t t r i b u t e : function ( attributeName ) {
117 return d a t a A t t r i b u t e s [ attributeName ] ;
118 },
119
120 /* * @ d e s c r i p t i o n S e t t e r :
121 * i n i t i a l i s e l a v a l e u r pour un a t t r i b u t d ’ une i n s t a n c e a p r è s un t e s t .
122 * En c a s d ’ e r r e u r , un message pour c e t a t t r i b u t e s t a j o u t é dans d a t a E r r o r .
123 * 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 .
124 * I l s ’ a g i t d ’ un s i m p l e a l i a s v e r s l a f o n c t i o n p r i v é e s e t A t t r i b u t e A n d E r r o r .
125 * @method s e t A t t r i b u t e
126 * @public
127 * @param { s t r i n g } a t t r i b u t e N a m e − nom de l ’ a t t r i b u t a t t e n d u e d ’ une i n s t a n c e
128 * @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 t t r i b u t a t t e n d u d ’ une
instance
129 * @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
130 */
131 setAttribute : setAttributeAndError ,
132
133 /* * @ d e s c r i p t i o n permet de s a v o i r s i un d e s a t t r i b u t s au moins comporte une
erreur .
134 * @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
135 */
136 h a s E r r o r : function ( ) {
137 fo r ( var attributeName in d a t a E r r o r ) {
138 i f ( d a t a E r r o r . hasOwnProperty ( attributeName ) ) {
139 return true ;
140 }
141 }
142 return f a l s e ;
143 },
144
145 /* * @ d e s c r i p t i o n Donne l ’ a c c è s au message d ’ e r r e u r d ’ un a t t r i b u t ( s ’ i l e x i s t e
).
43
Rémy Malgouyres, https://malgouyres.org Programmation JavaScript, Patterns, Web
44
Chapitre 2 : Programmation Fonctionnelle et Objet en JavaScript
198 },
199
200 /* * @ d e s c r i p t i o n F a b r i q u e q u i c r é e d e s o b j e t s d ’ un module mé t i e r , s u i v a n t l e ”
p a t t e r n module ” .
201 * 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 v a l e u r s d e s
attributs
202 * de l ’ i n s t a n c e à c r é e r .
203 * @param { O b j e c t } i n p u t O b j e t − sp é c i f i c a t i o n d e s v a l e u r s d e s a t t r i b u t s d ’ une
i n s t a n c e de module mé t i e r
204 * @param { s t r i n g } i n p u t O b j e t . 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
205 * @param { s t r i n g } i n p u t O b j e t . a t t r i b u t e N a m e − v a l e u r à a f f e c t e r à l ’ a t t r i b u t
attributeName
206 * ( exemple pour une a d r e s s e : i n p u t O b j . numeroRue , i n p u t O b j
. codePostal , etc .
207 */
208 c r e a t e I n s t a n c e : function ( i n p u t O b j e t ) {
209 return t h a t . c r e a t e I n s t a n c e ( i n p u t O b j e t ) ;
210 },
211
212 /* * @ d e s c r i p t i o n Cré e une c o p i e de l ’ o b j e t à l ’ i d e n t i q u e .
213 * @returns { O b j e c t } une i n s t a n c e a v e c d e s v a l e u r s d ’ a t t r i b u t s i d e n t i q u e à
this .
214 */
215 c l o n e : function ( ) {
216 return t h i s . c r e a t e I n s t a n c e ( d a t a A t t r i b u t e s ) ;
217 }
218 } ; // 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
219
220 return p u b l i c I n t e r f a c e I n s t a n c e ;
221
222 } // 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
223 ] ) ; // 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
45
Rémy Malgouyres, https://malgouyres.org Programmation JavaScript, Patterns, Web
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 . complementAddr − 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 ” ,
17 myApp . m e t i e r .
c r e a t e I n s t a n c e G e n e r i q u e ] ) ; //
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
46
Chapitre 2 : Programmation Fonctionnelle et Objet en JavaScript
47
Rémy Malgouyres, https://malgouyres.org Programmation JavaScript, Patterns, Web
73 a d r e s s e . s e t A t t r i b u t e ( ”numeroRue” , ”@#*m” ) ;
74
75 codeHTML += t h i s . t e s t . t e s t A f f i c h e A d r e s s e ( a d r e s s e ) ;
76
77 // Test de c l o n a g e :
78 codeHTML += t h i s . t e s t . t e s t A f f i c h e A d r e s s e ( a d r e s s e . c l o n e ( ) ) ;
79
80 // U t i l i s a t i o n de l a v a l e u r r e t o u r n é e pour g éné r e r l a vue
81 document . getElementById ( ” p a r a g r a p h e R e s u l t a t ” ) . innerHTML = codeHTML ;
82 } ) ;
83
84 // Exé c u t i o n de l a mé t h o d e mainFunction
85 myApp . mainFunction ( ) ;
48
Chapitre 2 : Programmation Fonctionnelle et Objet en JavaScript
49
Rémy Malgouyres, https://malgouyres.org Programmation JavaScript, Patterns, Web
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 . complementAddr − 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 A t t r i b u t e ( ’ numeroRue ’ ) ) {
78 htmlCode += a d r e s s e . g e t A t t r i b u t e ( ’ numeroRue ’ ) + ” , ” ;
79 }
80
81 htmlCode += a d r e s s e . g e t A t t r i b u t e ( ’ rue ’ ) + ” , ” ;
82 i f ( a d r e s s e . g e t A t t r i b u t e ( ’ complementAddr ’ ) ) {
83 htmlCode += a d r e s s e . g e t A t t r i b u t e ( ’ complementAddr ’ ) + ” , ” ;
84 }
85 htmlCode += a d r e s s e . g e t A t t r i b u t e ( ’ c o d e P o s t a l ’ ) + ” ” +
86 adresse . getAttribute ( ’ v i l l e ’ ) + ” , ” +
87 a d r e s s e . g e t A t t r i b u t e ( ’ pays ’ ) ;
88 return htmlCode ;
89 }]) ;
50
Chapitre 2 : Programmation Fonctionnelle et Objet en JavaScript
8 myApp . addModule ( ” t e s t ” , {
9 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 ) {
10 return ”<span s t y l e =\”width :260 px ; display : i n l i n e −b l o c k ; vertical −align :
top ;\”>” +
11 ”<p><s trong>Adresse Dé v e l o p p é e :</s trong><br />” +
12 myApp . view . a d r e s s e . getHtmlDevelopped ( a d r e s s e ) + ”</p>” +
13 ”<p><s trong>Adresse Compacte :</s trong><br />” +
14 myApp . view . a d r e s s e . getHtmlCompact ( a d r e s s e ) + ”</p>” +
15 ”</span>” ;
16 } // f i n de l a mé t h o d e t e s t A f f i c h e A d r e s s e
17 } // f i n du module myApp . t e s t
18 ) ; // f i n de l ’ i n v o c a t i o n de myApp . addModule
19
20
21 /* * @ d e s c r i p t i o n Programme p r i n c i p a l q u i c o n s t r u i t l e s donn é e s
22 * e t g é nère l a vue .
23 * @method myApp . mainFunction
24 * @public
25 */
26 myApp . addModule ( ” mainFunction ” , function ( ) {
27 // c r é a t i o n d ’ une i n s t a n c e
28 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 ( {
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 // o u b l i du champs complementAddr
33 c o d e P o s t a l : ” 630000 ” ,
34 v i l l e : ” Clermont−Ferrand ” ,
35 pays : ” France 2 ”
36 }) ;
37
38 var codeHTML = t h i s . t e s t . t e s t A f f i c h e A d r e s s e ( a d r e s s e ) ;
39
40 a d r e s s e . s e t A t t r i b u t e ( ” complementAddr ” , ” \”Bâ t i m e n t 3D\” ” ) ;
41 a d r e s s e . s e t A t t r i b u t e ( ” c o d e P o s t a l ” , ” 63000 ” ) ;
42 a d r e s s e . s e t A t t r i b u t e ( ” pays ” , ” France ” ) ;
43 a d r e s s e . s e t A t t r i b u t e ( ”numeroRue” , ”@#*m” ) ;
44
45 codeHTML += t h i s . t e s t . t e s t A f f i c h e A d r e s s e ( a d r e s s e ) ;
46 // U t i l i s a t i o n de l a v a l e u r r e t o u r n é e pour g éné r e r l a vue
47 document . getElementById ( ” p a r a g r a p h e R e s u l t a t ” ) . innerHTML = codeHTML ;
48 } ) ;
49
50 // Exé c u t i o n de l a mé t h o d e mainFunction
51 myApp . mainFunction ( ) ;
51
Rémy Malgouyres, https://malgouyres.org Programmation JavaScript, Patterns, Web
52
Chapitre 2 : Programmation Fonctionnelle et Objet en JavaScript
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 /* *
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 fo r ( 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 une interface attendues de nos modules
métier. Cette interface contient deux types de méthodes :
1. L’interface attendue des instances du module métier permet de tester la présence d’un
certain nombre de méthodes communes à toutes les instances (similaires à des méthodes
de classe), qui sont définies dans le prototype des instances ;
2. L’interface attendue des instances permet de s’assurer de la présence d’un certain nombre
de méthodes sur les instances, qui sont définies soit au niveau du prototype (si le code
source est indépendant de l’instance) ou au niveau de l’instance (si besoin de personnaliser
le code).
53
Rémy Malgouyres, https://malgouyres.org Programmation JavaScript, Patterns, Web
4 * @method t e s t I n t e r f a c e I m p l e m e n t a t i o n
5 * @augments myApp . m e t i e r
6 * @public
7 * @param { O b j e c t } i n s t a n c e − I n s t a n c e d ’ o b j e t mé t i e r s u p p o s é e
8 * @param { f u n c t i o n } i n s t a n c e . getModule − r e t o u r n e l e module mé t i e r (mé t h o d e s
statiques )
9 * @param { f u n c t i o n } i n s t a n c e . g e t A t t r i b u t e
10 * @param { f u n c t i o n } i n s t a n c e . s e t A t t r i b u t e
11 * @param { f u n c t i o n } i n s t a n c e . h a s E r r o r
12 * @param { f u n c t i o n } i n s t a n c e . g e t E r r o r M e s s a g e
13 * @param { f u n c t i o n } i n s t a n c e . g e t E r r o r L i s t
14 *
15 * @param { f u n c t i o n } i n s t a n c e . getModule ( ) . g e t A t t r i b u t e L i s t
16 * @param { f u n c t i o n } i n s t a n c e . getModule ( ) . g e t L a b e l T e x t
17 * @param { f u n c t i o n } i n s t a n c e . getModule ( ) . t e s t R e g e x
18 * @param { f u n c t i o n } i n s t a n c e . getModule ( ) . c r e a t e I n s t a n c e
19 *
20 * @return
21 */
22 myApp . addModule . apply (myApp . m e t i e r , [ ” t e s t I n t e r f a c e I m p l e m e n t a t i o n ” , function (
instance ){
23
24 // 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 .)
25 var metierCommonMethods = new I n t e r f a c e ( [
26 // 1) Mé t h o d e s s t a t i q u e s ( r é s u l t a t s i n d é pendant de l ’ i n s t a n c e )
27 ” getAttributeList ” , ” getLabelText ” , ” testRegex ” , ” createInstance ” ,
28 // 2) Mé t h o d e s d ’ i n s t a n c e ( r é s u l t a t s d é pendant de l ’ i n s t a n c e )
29 ” getModule ” , ” g e t A t t r i b u t e ” , ” s e t A t t r i b u t e ” , ” h a s E r r o r ” , ” g e t E r r o r M e s s a g e ” ,
” getErrorList ”
30 ]) ;
31
32 // c r é a t i o n d ’ une i n s t a n c e ( en l ’ o c c u r r e n c e une a d r e s s e )
33 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 ( {
34 i d : ” 04 a b f 8 5 b c 9 ” ,
35 numeroRue : ” 2 b i s ” ,
36 r u e : ”Rue de l ’ a Paix ” ,
37 complementAdresse : ”Bâ t i m e n t 3D” ,
38 c o d e P o s t a l : ” 63000 ” ,
39 v i l l e : ” Clermont−Ferrand ” ,
40 pays : ” France ”
41 }) ;
42
43 return metierCommonMethods . isImplementedBy ( monObjet ) ;
44 } ] ) ;
54
Chapitre 2 : Programmation Fonctionnelle et Objet en JavaScript
9 i d : ” 04 a b f 8 5 b c 9 ” ,
10 numeroRue : ” 2 b i s ” ,
11 r u e : ”Rue de l ’ a Paix ” ,
12 complementAdresse : ”Bâ t i m e n t 3D” ,
13 c o d e P o s t a l : ” 63000 ” ,
14 v i l l e : ” Clermont−Ferrand ” ,
15 pays : ” France ”
16 }) ;
17
18 var t e s t I n t e r f a c e s M e t i e r = myApp . m e t i e r . t e s t I n t e r f a c e I m p l e m e n t a t i o n ( monObjet ) ;
19 var codeHTML ;
20 i f ( t e s t I n t e r f a c e s M e t i e r === true ) {
21 codeHTML = ”<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>” ;
22 } else {
23 codeHTML = ”<p>” + t e s t I n t e r f a c e s M e t i e r + ”</p>”
24 }
25 // U t i l i s a t i o n de l a v a l e u r r e t o u r n é e pour g éné r e r l a vue
26 document . getElementById ( ” p a r a g r a p h e R e s u l t a t ” ) . innerHTML = codeHTML ;
27 } ) ;
28
29 // Exé c u t i o n de l a mé t h o d e mainFunction
30 myApp . mainFunction ( ) ;
”
Code Source 2.29 : Fichiers JS inclus dans ex11-interfaceImplementationTest.html
1 <!−− Cré a t i o n de l ’ a p p l i c a t i o n v i d e a v e c deux mé t h o d e s −−>
2 <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>
3 <!−− 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 −−>
4 <s c r i p t src=” . /ex05−modulePatternRegex . j s ”></s c r i p t>
5 <!−− Cré a t i o n de sous−module a d r e s s e de myApp . m e t i e r −−>
6 <s c r i p t src=” . /ex06−createModuleMetier . j s ”></s c r i p t>
7 <!−− Cré a t i o n d ’ une mé t h o d e f a b r i q u e g éné r i q u e d ’ o b j e t s mé t i e r −−>
8 <s c r i p t src=” . / e x 0 7 − f a b r i q u e O b j e t M e t i e r . j s ”></s c r i p t>
9 <!−− Cré a t i o n de sous−module a d r e s s e de myApp . m e t i e r −−>
10 <s c r i p t src=” . /ex06−moduleMetierAdresse . j s ”></s c r i p t>
11 <!−− Cré a t i o n d ’ une mé t h o d e 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 −−>
12 <s c r i p t src=” . / e x 0 8 − f a b r i q u e A d r e s s e . j s ”></s c r i p t>
13 <!−− 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 . v i e w . a d r e s s e −−>
14 <s c r i p t src=” . /ex09−adresseView . j s ”></s c r i p t>
15 <!−− C l a s s e de v é r i f i c a t i o n de l ’ i m p l é me n t a t i o n d ’ i n t e r f a c e s −−>
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 <!−− C l a s s e de v é r i f i c a t i o n de l ’ i m p l é me n t a t i o n d ’ i n t e r f a c e s −−>
18 <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 M e t i e r . j s ”></s c r i p t>
19 −−
20 <!−− Ajout d ’ une f o n c t i o n de t e s t , d ’ une mé t h o d e ”main ” , e t ex é c u t i o n −−>
21 <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 T e s t . j s ”></s c r i p t>
55
Rémy Malgouyres, https://malgouyres.org Programmation JavaScript, Patterns, Web
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 ’ o b j e t mé t i e r .
6 * Pour chaque a t t r i b u t d ’ une i n s t a n c e , l a d e s c r i p t i o n de l a p r o p r i é t é
7 * e t sa v a l e u r s o n t a f f i c h é e s .
8 *
9 * @method g e t H t m l D e v e l o p p e d
10 * @augments myApp . v i e w
11 * @public
12 * @param { O b j e c t } i n s t a n c e − i n s t a n c e d ’ o b j e t mé t i e r q u i i m p l é mente :
13 * ” getModule ” , ” g e t A t t r i b u t e ” , ” s e t A t t r i b u t e ” ,
14 * ” hasError ” , ” getErrorMessage ” , ” g e t E r r o r L i s t ”
15 * a i n s i que l e s mé t h o d e s s t a t i q u e s :
16 * ” getAttributeList ” , ” getLabelText ” , ” testRegex ” ,
17 * ” c r e a t e I n s t a n c e ” , ” getModule ” .
18 */
19 myApp . addModule . apply (myApp . view , [ ” g e t H t m l G e n e r i c ” , function ( i n s t a n c e ) {
20 var t e s t I n t e r f a c e s M e t i e r = myApp . m e t i e r . t e s t I n t e r f a c e I m p l e m e n t a t i o n ( i n s t a n c e ) ;
21 i f ( t e s t I n t e r f a c e s M e t i e r !== true ) {
22 // Retourner un message d ’ e r r e u r au l i e u du code HTML de l ’ i n s t a n c e
23 return t e s t I n t e r f a c e s M e t i e r ;
24 }
25 // Code HTML pour l ’ a f f i c h a g e de l ’ i n s t a n c e :
26 var codeHTML = ”<div><span><h2>Donné e s de l ’ i n s t a n c e :</h2>” ;
27 fo r ( var i =0 ; i < i n s t a n c e . getModule ( ) . g e t A t t r i b u t e L i s t ( ) . l e n g t h ; ++i ) {
28 var attributeName = i n s t a n c e . getModule ( ) . g e t A t t r i b u t e L i s t ( ) [ i ] ;
29 codeHTML += ”<s trong>”
30 + i n s t a n c e . getModule ( ) . g e t L a b e l T e x t ( attributeName ) + ” : ”
31 + ”</s trong> ”
32 + i n s t a n c e . g e t A t t r i b u t e ( attributeName ) + ”<br />” ;
33 }
34 codeHTML += ”</span>” ;
35
36 // 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
37 codeHTML += ”<span><h2>E r r e u r s :</h2>” ;
38 fo r ( var i =0 ; i < i n s t a n c e . getModule ( ) . g e t A t t r i b u t e L i s t ( ) . l e n g t h ; ++i ) {
39 var attributeName = i n s t a n c e . getModule ( ) . g e t A t t r i b u t e L i s t ( ) [ i ] ;
40 codeHTML += ”<s trong>”
41 + i n s t a n c e . getModule ( ) . g e t L a b e l T e x t ( attributeName ) + ” : ”
42 + ”</s trong> ” +
43 i n s t a n c e . g e t E r r o r M e s s a g e ( attributeName ) + ”<br />” ;
44 }
45 codeHTML += ”</span></div>” ;
46 return codeHTML ;
47 } ] ) ;
56
Chapitre 2 : Programmation Fonctionnelle et Objet en JavaScript
57
Rémy Malgouyres, https://malgouyres.org Programmation JavaScript, Patterns, Web
13 <!−− C l a s s e de v é r i f i c a t i o n de l ’ i m p l é me n t a t i o n d ’ i n t e r f a c e s −−>
14 <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>
15 <!−− C l a s s e de v é r i f i c a t i o n de l ’ i m p l é me n t a t i o n d ’ i n t e r f a c e s −−>
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 M e t i e r . 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 g éné r i q u e dans myApp . m e t i e r . v i e w −−>
18 <s c r i p t src=” . / e x 1 2 − o b j e t M e t i e r V i e w . j s ”></s c r i p t>
19 −−
20 <!−− Ajout d ’ une f o n c t i o n de t e s t , d ’ une mé t h o d e ”main ” , e t ex é c u t i o n −−>
21 <s c r i p t src=” . / e x 1 2 − o b j e t M e t i e r V i e w T e s t . j s ”></s c r i p t>
58
Chapitre 3
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.
Code Source 3.1 : /pattern-proto/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
59
Rémy Malgouyres, https://malgouyres.org Programmation JavaScript, Patterns, Web
27 t h i s . t e l 2=t e l 2 ;
28 }
29
30 /* *
31 * @method g etH tml
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 }
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
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.
60
Chapitre 3 : Constructeurs, Prototype et Patterns Associés
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 };
61
Rémy Malgouyres, https://malgouyres.org Programmation JavaScript, Patterns, Web
62
Chapitre 3 : Constructeurs, Prototype et Patterns Associés
63
Rémy Malgouyres, https://malgouyres.org Programmation JavaScript, Patterns, Web
36 /* * @ d e s c r i p t i o n R e n v o i e l e t e x t e de d e s c r i p t i o n de l ’ a t t r i b u t a t t e n d u e
des i n s t a n c e s .
37 * 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 )
38 * @method g e t L a b e l T e x t
39 * @param { s t r i n g } a t t r i b u t e N a m e − nom de p r o p r i é t é
40 * @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
41 */
42 g e t L a b e l T e x t : function ( attributeName ) {
43 return a t t r i b u t e s P a t t e r n s [ attributeName ] . l a b e l T e x t ;
44 },
45
46
47 /* * @ d e s c r i p t i o n 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 a t t r i b u t s d e s
instances .
48 * 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 .
49 * @method t e s t R e g e x
50 * @param { s t r i n g } a t t r i b u t e N a m e − nom de p r o p r i é t é
51 * @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 t t r i b u t
52 * @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 a t t r i b u t v a l i d e ,
53 * un message d ’ e r r e u r s i n o n .
54 */
55 t e s t R e g e x : function ( attributeName , v a l u e ) {
56 i f ( a t t r i b u t e s P a t t e r n s [ attributeName ] === u n d e f i n e d ) {
57 return ”La p r o p r i é t é ” + attributeName + ” n ’ e x i s t e pas ” ;
58 } else {
59 return a t t r i b u t e s P a t t e r n s [ attributeName ] . r e g e x T e s t ( v a l u e ) ;
60 }
61 }
62 } ; // Fin du l i t t é r a l myApp . m e t i e r . m e t h o d e s S t a t i q u e s M o d u l e s M e t i e r
63 } // f i n du ” i f (myApp . m e t i e r . m e t h o d e s S t a t i q u e s M o d u l e s M e t i e r === u n d e f i n e d ) ”
64
65 var ModuleMetier = function ( ) {} ;
66
67 // Le modèle de t o u t e s l e s mé t h o d e s s t a t i q u e s communes à t o u s l e s o b j e t s
68 // mé t i e r s e r t de p r o t o t y p e à t o u s l e s modules mé t i e r .
69 // Cela permet de r e n d r e c e s mé t h o d e s ( e x e m p l a i r e u n i q u e ) a c c e s s i b l e s
70 // dans t o u s l e s modules mé t i e r
71 ModuleMetier . p r o t o t y p e
72 = myApp . m e t i e r . m e t h o d e s S t a t i q u e s M o d u l e s M e t i e r ;
73
74 // Cré a t i o n du module a v e c l e c o n s t r u c t e u r de modules mé t i e r s
75 // p o u t p o u v o i r d é f i n i r un p r o t o t y p e commun pour t o u s
76 // l e s modules mé t i e r .
77 myApp . m e t i e r [ moduleName ] = new ModuleMetier ( ) ;
78 /* *
79 * Tableau c o n t e n a n t l a l i s t e d e s a t t r i b u t s d ’ une i n s t a n c e .
80 * 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 .
81 * @member
82 * @private
83 */
84 var a t t r i b u t e L i s t = function ( ) {
85 var l i s t e = [ ] ;
86
87 // Parcours d e s p r o p r i é t é s de l ’ o b j e t a t t r i b u t e s P a t t e r n s . r e g e x T e s t
88 // q u i c o r r e s p o n d e n t aux a t t r i v u t s de l ’ i n s t a n c e
89 fo r ( var attributeName in a t t r i b u t e s P a t t e r n s ) {
64
Chapitre 3 : Constructeurs, Prototype et Patterns Associés
90 // 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 .
91 i f ( a t t r i b u t e s P a t t e r n s . hasOwnProperty ( attributeName ) ) {
92 l i s t e . push ( attributeName ) ;
93 }
94 }
95 return l i s t e ;
96 } ( ) ; // a p p e l immé d i a t de l a f o n c t i o n anonyme .
97
98 /* * @ d e s c r i p t i o n P r o p r i é t é c o n t e n a n t l e s sp é c i f i c a t i o n s
99 * de chaque a t t r i b u t t e l l e s que donn é e s en p a r a m è t r e s
100 */
101 //myApp . m e t i e r [ moduleName ] . a t t r i b u t e s P a t t e r n s = a t t r i b u t e s P a t t e r n s ;
102
103 } ] // f i n de l a f o n c t i o n q u i c r é e l ’ o b j e t myApp . m e t i e r [ moduleName ]
104 ) ; // 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
105 // ( a j o u t de l ’ o b j e t t h i s au m et ier , s o u s l e nom c r e a t e M o d u l e M e t i e r )
65
Rémy Malgouyres, https://malgouyres.org Programmation JavaScript, Patterns, Web
15 that = this ;
16
17 // ////////////////////////////////////////////////////////
18 // S i l e modèle de t o u t e s l e s mé t h o d e s p r i v é e s communes
19 // à t o u t e s l e s i n s t a n c e s d ’ o b j e t s mé t i e r n ’ a pas e n c o r e é t é c r é é
20 // ( Cet o b j e t e x i s t e en un e x e m p l a i r e u n i q u e . )
21 i f (myApp . m e t i e r . m e t h o d e s I n s t a n c e s M e t i e r === u n d e f i n e d ) {
22 // C o n s t r u c t e u r d ’ un o b j e t u n i q u e a v e c un p r o t o t y p e
23 var P r i v a t e I n s t a n c e s C o n s t r u c t o r = function ( ) {
24 /* * @ d e s c r i p t i o n c o n t i e n t l e s v a l e u r s d e s a t t r i b u t s de l ’ i n s t a n c e ,
initialement vide
25 * @member
26 * @private
27 */
28 t h i s . d a t a A t t r i b u t e s = {} ;
29 /* * @ d e s c r i p t i o n c o n t i e n t l e s messages d ’ e r r e u r a s s o c i é s aux a t t r i b u t s
de l ’ i n s t a n c e s
30 * @member
31 * @private
32 */
33 t h i s . d a t a E r r o r = {} ;
34 };
35
36 P r i v a t e I n s t a n c e s C o n s t r u c t o r . p r o t o t y p e . addError
37 = function ( attributeName , message ) {
38 // Ajout d ’ une p r o p r i é t é
39 t h i s . d a t a E r r o r [ attributeName ] = message ;
40 };
41
42 PrivateInstancesConstructor . prototype . setAttribute
43 = function ( attributeName , v a l u e ) {
44 var r e s u l t T e s t R e g e x = t h a t . t e s t R e g e x ( attributeName , v a l u e ) ;
45 // On i n t i a l i s e l ’ a t t r i b u t de l ’ i n s t a n c e
46 t h i s . d a t a A t t r i b u t e s [ attributeName ] = v a l u e ;
47 // 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
48 i f ( r e s u l t T e s t R e g e x === true ) {
49 // 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
50 delete t h i s . d a t a E r r o r [ attributeName ] ;
51 } else {
52 // 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 .
53 // a v e c l e message d ’ e r r e u r .
54 t h i s . addError ( attributeName , ” A t t r i b u t ” + v a l u e +
55 ” i n v a l i d e : ” + resultTestRegex ) ;
56 }
57 };
58
59 PrivateInstancesConstructor . prototype . getAttribute
60 = function ( attributeName ) {
61 return t h i s . d a t a A t t r i b u t e s [ attributeName ] ;
62 };
63
64 PrivateInstancesConstructor . prototype . hasError
65 = function ( ) {
66 fo r ( var attributeName in t h i s . d a t a E r r o r ) {
67 i f ( t h i s . d a t a E r r o r . hasOwnProperty ( attributeName ) ) {
68 return true ;
66
Chapitre 3 : Constructeurs, Prototype et Patterns Associés
69 }
70 }
71 return f a l s e ;
72 };
73
74 PrivateInstancesConstructor . prototype . getErrorList
75 = function ( ) {
76 var e r r o r L i s t = [ ] ;
77 fo r ( var attributeName in t h i s . d a t a E r r o r ) {
78 i f ( t h i s . d a t a E r r o r . hasOwnProperty ( attributeName ) ) {
79 e r r o r L i s t . push ( attributeName ) ;
80 }
81 }
82 return e r r o r L i s t ;
83 };
84
85 PrivateInstancesConstructor . prototype . getErrorMessage
86 = function ( attributeName ) {
87 return t h i s . d a t a E r r o r [ attributeName ] ;
88 };
89 /* * @ d e s c r i p t i o n 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
nouvelle instance
90 * ( 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 )
91 * @private
92 */
93 P r i v a t e I n s t a n c e s C o n s t r u c t o r . p r o t o t y p e . generateRandomId
94 = function ( ) {
95 var id Le ngt h = 10 ;
96 var r e s u l t a t = ” ” ;
97 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 ” ) ;
98 var i ;
99 fo r ( var i =0 ; i<10 ; ++i ) {
100 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 ) ] ;
101 }
102 return r e s u l t a t ;
103 }
104
105 // On mé morise l e c o n s t r u c t e u r d ’ i n s t a n c e s p r i v é e s pour n ’ en a v o i r qu ’ un
106 myApp . m e t i e r . 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 i v a t e I n s t a n c e s C o n s t r u c t o r ;
107 } // f i n du ” i f (myApp . m e t i e r . m e t h o d e s I n s t a n c e s M e t i e r === u n d e f i n e d ) ”
108
109 // On c r é e une i n s t a n c e p r i v é e ( v a r i a b l e l o c a l e , v o i r ” p a t t e r n module ” )
110 var p r i v a t e I n s t a n c e = new myApp . m e t i e r . 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 ( ) ;
111
112
113 /* * @ d e s c r i p t i o n 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 q u i
114 * c o n t i e n d r a l e s mé t h o d e s p e r m e t t a n t de m a n i p u l e r l ’ i n s t a n c e c r é é e ,
115 * q u i c o n t i t u e l ’ i n t e r f a c e du p a t t e r n module .
116 *
117 *L ’ i n t é r ê t 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 au n i v e a u du
prototype ,
118 * v i a l ’ o b j e t u n i q u e myApp . m e t i e r . m e t h o d e s I n s t a n c e s M e t i e r , c r é é une s e u l e
fois .
119 *
120 * De p l u s , pe p r o t o t y p e d e s i n s t a n c e s h é r i t e l u i −même d e s mé t h o d e s
67
Rémy Malgouyres, https://malgouyres.org Programmation JavaScript, Patterns, Web
statiques
121 * du module mé t i e r .
122 */
123 var P u b l i c I n s t a n c e I n t e r f a c e = function ( ) {} ;
124
125 // MISE À DISPOSITION DES MÉTHODES STATIQUES DU MODULE
126 // VIA LE PROTOTYPE
127 P u b l i c I n s t a n c e I n t e r f a c e . p r o t o t y p e = t h i s ; // exemple : t h i s = myApp . m e t i e r .
adresse
128
129 /* * @ d e s c r i p t i o n 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 ”
130 * (comme l ’ a c c è s d i r e c t à l a l i s t e d e s a t t r i b u t s ou l e s t e s t s r e g e x )
131 * @return { O b j e c t } l e module myApp . m e t i e r . moduleName
132 */
133 P u b l i c I n s t a n c e I n t e r f a c e . p r o t o t y p e . getModule = function ( ) {
134 return t h i s ;
135 };
136
137
138 // I n t e r f a c e p u b l i q u e du module , r e t o u r n é e par l a f a b r i q u e
139 var i n s t a n c e I n t e r f a c e = new P u b l i c I n s t a n c e I n t e r f a c e ( ) ;
140
141 i n s t a n c e I n t e r f a c e . getModule = function ( ) {
142 return t h i s ;
143 };
144
145 // ///////////////////////////////////////////////
146 // On e x p o s e l e s mé t h o d e s du p r o t o t y p e de l ’ i n s t a n c e p r i v é e
147 // v i a l ’ i n t e r f a c e d e s i n s t a n c e s :
148
149 /* * @ d e s c r i p t i o n A j o u t e une p r o p r i é t é ( message d ’ e r r e u r ) dans t h i s . d a t a E r r o r
150 * c o r r e s p o n d a n t à un a t t r i b u t .
151 * @method addError
152 * @public
153 */
154 i n s t a n c e I n t e r f a c e . addError = function ( ) {
155 p r i v a t e I n s t a n c e . addError ( ) ;
156 };
157
158 /* * @ d e s c r i p t i o n S e t t e r : i n i t i a l i s e l a v a l e u r d e s a t t i b u t s d ’ une i n s t a n c e .
159 * 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 t h i s .
dataError .
160 * 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 .
161 * @method s e t A t t r i b u t e
162 * @public
163 */
164 i n s t a n c e I n t e r f a c e . s e t A t t r i b u t e = function ( attributeName , v a l u e ) {
165 p r i v a t e I n s t a n c e . s e t A t t r i b u t e ( attributeName , v a l u e ) ;
166 };
167
168 /* * @ d e s c r i p t i o n 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 .
169 * @method g e t A t t r i b u t e
170 * @public
171 * @param { s t r i n g } a t t r i b u t e N a m e − nom de l ’ a t t r i b u t a t t e n d u e d ’ une
instance
172 * @return { s t r i n g } l a v a l e u r de l ’ a t t r i b u t ou u n d e f i n e d en c a s de nom d ’
68
Chapitre 3 : Constructeurs, Prototype et Patterns Associés
a t t r i b u t inconnu .
173 */
174 i n s t a n c e I n t e r f a c e . g e t A t t r i b u t e = function ( attributeName ) {
175 return p r i v a t e I n s t a n c e . g e t A t t r i b u t e ( attributeName ) ;
176 };
177
178 /* * @ d e s c r i p t i o n Dé t e r m i n e s i l ’ i n s t a n c e comprend au moins une e r r e u r .
179 * @public
180 * @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
181 */
182 i n s t a n c e I n t e r f a c e . h a s E r r o r = function ( attributeName ) {
183 return p r i v a t e I n s t a n c e . h a s E r r o r ( attributeName ) ;
184 };
185
186 /* * @ d e s c r i p t i o n 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
187 * @public
188 * @return { s t r i n g [ ] } t a b l e a u d e s noms de p r o p r i é t é s q u i comportent une
erreur .
189 */
190 i n s t a n c e I n t e r f a c e . g e t E r r o r L i s t = function ( ) {
191 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 ( ) ;
192 };
193
194 /* * @ d e s c r i p t i o n Donne l ’ a c c è s au message d ’ e r r e u r d ’ un a t t r i b u t ( s ’ i l e x i s t e
).
195 * @method g e t E r r o r M e s s a g e
196 * @public
197 * @param { s t r i n g } a t t r i b u t e N a m e − nom d ’ a t t r i b u t d ’ une i n s t a n c e de module mé
tier
198 * @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 un a t t r i b u t s ’ i l
existe
199 * 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
200 */
201 i n s t a n c e I n t e r f a c e . g e t E r r o r M e s s a g e = function ( attributeName ) {
202 return p r i v a t e I n s t a n c e . g e t E r r o r M e s s a g e ( attributeName ) ;
203 };
204
205 // I n i t i a l i s a t i o n d e s a t t r i b u t s de l ’ i n s t a n c e
206 // 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
207 i f ( inputObj !== null ) {
208 // Parcours d e s p r o p r i é t é s de g e t A t t r i b u t e L i s t ( )
209 // q u i c o r r e s p o n d e n t aux a t t r i b u t s de l ’ i n s t a n c e à c r é e r
210 fo r ( var i = 0 ; i < t h i s . g e t A t t r i b u t e L i s t ( ) . l e n g t h ; ++i ) {
211 var attributeName = t h i s . g e t A t t r i b u t e L i s t ( ) [ i ] ;
212 // U t i l i s a t i o n du s e t t e r pour i n i t i a l i s e r l ’ a t t r i b u t
213 p r i v a t e I n s t a n c e . s e t A t t r i b u t e ( attributeName , inputObj [ attributeName ] ) ;
214 }
215 } else {
216 // On i n i t i a l i s e l e s v a l e u r s d e s a t t r i b u t s à ””
217 fo r ( var i = 0 ; i < t h i s . g e t A t t r i b u t e L i s t ( ) . l e n g t h ; ++i ) {
218 var attributeName = t h i s . g e t A t t r i b u t e L i s t ( ) [ i ] ;
219 i f ( attributeName === ” i d ” ) {
220 p r i v a t e I n s t a n c e . d a t a A t t r i b u t e s [ attributeName ] = p r i v a t e I n s t a n c e .
generateRandomId ( ) ;
221 } else {
222 p r i v a t e I n s t a n c e . d a t a A t t r i b u t e s [ attributeName ] = ” ” ;
69
Rémy Malgouyres, https://malgouyres.org Programmation JavaScript, Patterns, Web
223 }
224 }
225 }
226
227 // 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
228 return i n s t a n c e I n t e r f a c e ;
229 } // 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
230 ] ) ; // 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
Les fichiers du répertoire ../pattern-fonct correspondent aux exemples définis dans le cha-
pitre 2, qui sont réutilisables tels quels du fait de la généricité et de l’homogénéité des interfaces
d’objets métier.
70
Chapitre 3 : Constructeurs, Prototype et Patterns Associés
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.
Code Source 3.11 : /pattern-proto/ex08-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 {
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 += ” , ” ;
71
Rémy Malgouyres, https://malgouyres.org Programmation JavaScript, Patterns, Web
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 }
72
Chapitre 4
73
Rémy Malgouyres, https://malgouyres.org Programmation JavaScript, Patterns, Web
29 var t i t r e V a l u e = $ ( ”#mainForm_resume” ) . v a l ( ) ;
30 // 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
31 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 ( {
32 chaine : titreValue ,
33 minLength : 1
34 }) ;
35 // M o d i f i c a t i o n du contenu du span d ’ ID ” error_mainForm_resume ”
36 i f ( r e s u l t R e g e x T e s t === true ) {
37 $ ( ”#error_mainForm_resume ” ) . empty ( ) ;
38 } else {
39 $ ( ”#error_mainForm_resume ” ) . html (
40 ” 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 ” +
41 ” 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 />” ) ;
42 }
43 };
74
Chapitre 4 : Formulaires, Filtrage, Pattern Mediator
75
Rémy Malgouyres, https://malgouyres.org Programmation JavaScript, Patterns, Web
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 },
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
76
Chapitre 4 : Formulaires, Filtrage, Pattern Mediator
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 : ” For mul aire 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 }() ] ) ;
77
Rémy Malgouyres, https://malgouyres.org Programmation JavaScript, Patterns, Web
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 <!−− i n p u t a v e c g e s t i o n n a i r e de l ’ é v é nement onchange −−>
12 <span id=” error_mainForm_titre ” class= ” errorMsg ”></span>
13 <l a b e l for=” mainForm_titre ”>T i t r e :</ l a b e l>
14 <i nput type=” t e x t ” id=” mainForm_titre ” s i z e=” 15 ”
15 placeholder=” T i t r e du f i l m ” onchange= ” f i l t e r Data ( ’ mainForm ’ , ’ t i t r e ’ ) ” /><br /
>
16 <!−− t e x t a r e a a v e c g e s t i o n n a i r e de l ’ é v é nement onchange −−>
17 <span id=” error_mainForm_resume ” class= ” errorMsg ”></span>
18 <l a b e l for=”mainForm_resume”>Résumé :</ l a b e l>
19 <textarea id=”mainForm_resume” rows=” 10 ” cols=” 50 ”
20 placeholder=” 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>
21 </form>
22 <!−− 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 −−>
23 <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>
24 <!−− 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 −−>
25 <s c r i p t src=” j q u e r y . j s ”></s c r i p t>
26 <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>
27 <s c r i p t src=” ex01−basicForm . j s ”></s c r i p t>
28 <s c r i p t>
29 // 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 .
30 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 ’ ) ;
31 // 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
32 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 ) ;
33 // 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é
34 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 )
;
35
36 /** @ d e s c r i p t i o n 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 ,
37 * 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 .
38 * @ f u n c t i o n f i l t e r Data
39 */
40 var f i l t e r Data = function ( formId , inputName ) {
41 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 ) ;
42 };
43 </s c r i p t>
44 </body>
45 </html>
4.3 Exemple :
Génération automatique de formulaire d’adresse
Dans l’exemple suivant, des méthodes d’un module myApp.gui permettent de générer auto-
matiquement les inputs d’un formulaire permettant de saisir les attributs (ici supposées de
type texte) d’un objet qui implémente des interface qui apparaissent dans l’exemple de la
78
Chapitre 4 : Formulaires, Filtrage, Pattern Mediator
partie 2.7.1.
Nous appliquons cette méthode pour afficher et filtrer automatiquement un formulaire de
saisie d’une adresse.
79
Rémy Malgouyres, https://malgouyres.org Programmation JavaScript, Patterns, Web
80
Chapitre 4 : Formulaires, Filtrage, Pattern Mediator
87 * ” hasError ” , ” getErrorMessage ” , ” g e t E r r o r L i s t ”
88 * a i n s i que l e s mé t h o d e s s t a t i q u e s :
89 * ” getAttributeList ” , ” getLabelText ” , ” testRegex ” ,
90 * ” c r e a t e I n s t a n c e ” , ” getModule ” .
91 * @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 é
92 * @return { 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 .
93 */
94 myApp . addModule . apply (myApp . gui , [ ” getHtmlFormInputs ” , function ( o b j e t M e t i e r ,
formId ) {
95 // On v é r i f i e que l ’ o b j e t M e t i e r i m p l é mente b i e n n o t r e i n t e r f a c e g éné r i q u e .
96 var t e s t I n t e r f a c e s M e t i e r = myApp . m e t i e r . t e s t I n t e r f a c e I m p l e m e n t a t i o n (
objetMetier ) ;
97 i f ( t e s t I n t e r f a c e s M e t i e r !== true ) {
98 throw new E r r o r ( t e s t I n t e r f a c e s M e t i e r ) ;
99 }
100
101 // 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 .
102 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 ) ;
103
104 var htmlCode = ” ” ;
105
106 var a t t r i b u t e L i s t = o b j e t M e t i e r . g e t A t t r i b u t e L i s t ( ) ;
107
108 // 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
109 // 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 .
110 fo r ( var i =0 ; i < a t t r i b u t e L i s t . l e n g t h ; i ++){
111 var attributeName = a t t r i b u t e L i s t [ i ] ;
112 // 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 :
113 i f ( attributeName != ” i d ” ) {
114 // Concat é n a t i o n du code HTML de l ’ i n p u t
115 htmlCode += myApp . g u i . getInputCode ( {
116 objetMetier : objetMetier ,
117 attributeName : a t t r i b u t e L i s t [ i ] ,
118 labelText : objetMetier . getLabelText ( a t t r i b u t e L i s t [ i ] ) ,
119 formId : formId
120 } ) + ”<br />” ;
121 }
122 }
123
124 // 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
125 htmlCode += ”<i nput t y p e =\” h i d d e n \” i d =\”” + formId + ” _id \” v a l u e =\”” +
126 o b j e t M e t i e r . g e t A t t r i b u t e ( ” i d ” ) + ” \” />” ;
127
128 return htmlCode ;
129 }]) ;
81
Rémy Malgouyres, https://malgouyres.org Programmation JavaScript, Patterns, Web
8 r u e : ”Rue de l ’ a Paix ” ,
9 complementAddr : ”Bâ t i m e n t 3D” ,
10 c o d e P o s t a l : ” 63000 ” ,
11 v i l l e : ” Clermont−Ferrand ” ,
12 pays : ” France ”
13 }) ;
14
15 // 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
16 codeHTML = ”<form i d =\”mainForm\” method=\” p o s t \”>” +
17 myApp . g u i . getHtmlFormInputs ( a d r e s s e , ”mainForm” ) +
18 ”<i nput t y p e =\” s u b m i t \” v a l u e =\” v a l i d e r \” />” +
19 ”</form>” ;
20 // U t i l i s a t i o n de l a v a l e u r r e t o u r n é e pour g éné r e r l a vue
21 document . getElementById ( ” p a r a g r a p h e R e s u l t a t ” ) . innerHTML = codeHTML ;
22 } ) ;
23
24 // Exé c u t i o n de l a mé t h o d e mainFunction
25 myApp . mainFunction ( ) ;
82
Chapitre 4 : Formulaires, Filtrage, Pattern Mediator
Le test avec la modélisation des objets métiers de la partie 3.3, utilisant la notion de
prototype, diffère seulement au niveau de l’inclusion de la définition des modules métier dans
le fichier HTML :
Code Source 4.8 : Fichiers JS inclus dans ex03-formsGuiTestProto.html
1 <!−− S t r u c t u r e de l ’ a p p l i c a t i o n v i d e a v e c deux mé t h o d e s −−>
2 <s c r i p t src=” . . / p a t t e r n − f o n c 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>
3 <!−− 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 −−>
4 <s c r i p t src=” . . / p a t t e r n − f o n c t / e x 0 5 − m o d u l e P a t t e r n R e g e x . j s ”></s c r i p t>
5 <!−− Sous−module a d r e s s e de myApp . m e t i e r −−>
6 <s c r i p t src=” . . / p a t t e r n − p r o t o / e x 0 5 − c r e a t e M o d u l e M e t i e r P r o t o . j s ”></s c r i p t>
7 <!−− Mé t h o d e f a b r i q u e g éné r i q u e d ’ o b j e t s mé t i e r −−>
8 <s c r i p t src=” . . / p a t t e r n − p r o t o / e x 0 5 − f a b r i q u e O b j e t M e t i e r P r o t o . j s ”></s c r i p t>
9 <!−− Cré a t i o n de sous−module a d r e s s e de myApp . m e t i e r −−>
10 <s c r i p t src=” . . / p a t t e r n − f o n c t / e x 0 6 − m o d u l e M e t i e r A d r e s s e . j s ”></s c r i p t>
11 <!−− Cré a t i o n d ’ une mé t h o d e 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 −−>
12 <s c r i p t src=” . . / p a t t e r n − f o n c t / e x 0 8 − f a b r i q u e A d r e s s e . j s ”></s c r i p t>
13 <!−− C l a s s e de v é r i f i c a t i o n de l ’ i m p l é me n t a t i o n d ’ i n t e r f a c e s −−>
14 <s c r i p t src=” . . / p a t t e r n − f o n c t / 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>
15 <!−− C l a s s e de v é r i f i c a t i o n de l ’ i m p l é me n t a t i o n d ’ i n t e r f a c e s −−>
16 <s c r i p t src=” . . / p a t t e r n − f o n c t / 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 M e t i e r . j s ”></s c r i p t>
17 <!−− F o n c t i o n s d ’ a f f i c h a g e g éné r i q u e dans myApp . m e t i e r . v i e w −−>
18 <s c r i p t src=” . . / p a t t e r n − f o n c t / e x 1 2 − o b j e t M e t i e r V i e w . j s ”></s c r i p t>
19 −−
20 <!−− 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 −−>
21 <s c r i p t src=” j q u e r y . j s ”></s c r i p t>
22 <!−− Mediator sp é c i a l i s é pour f i l t r e r l e s i n p u t s ( e v t ” change ” ) −−>
23 <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>
24 <!−− Géné r a t i o n a u t o m a t i q u e de f o r m u l a i r e s a v e c f i l t r a g e d e s a t t r i b u t s −−>
25 <s c r i p t src=” ex03−formsGui . j s ”></s c r i p t>
26 −−
27 <!−− Ajout d ’ une f o n c t i o n de t e s t , d ’ une mé t h o d e ”main ” , e t ex é c u t i o n −−>
28 <s c r i p t src=” ex03−formsGuiTest . j s ”></s c r i p t>
83
Chapitre 5
• 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”.
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.
84
Chapitre 5 : Exemple d’Application avec IHM
85
Rémy Malgouyres, https://malgouyres.org Programmation JavaScript, Patterns, Web
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 complementAddr : ” 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 complementAddr : ” 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 })
86
Chapitre 5 : Exemple d’Application avec IHM
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 complementAddr : ” 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 }) ) ;
• De provoquer des mises à jour de panneaux de la vue qui observent des propriétés du
modèle.
87
Rémy Malgouyres, https://malgouyres.org Programmation JavaScript, Patterns, Web
88
Chapitre 5 : Exemple d’Application avec IHM
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 * 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 .
68 * 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
69 * ( 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 )
70 * @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
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 q u i s e r a a p p e l é e en r é
a c t i o n à l ’ é v é nement .
72 */
73 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 ) {
74 i f ( m _ s u b s c r i p t i o n L i s t s . hasOwnProperty ( eventCateg ) ) {
75 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 } ) ;
76 } else {
77 throw new E r r o r ( ” Cat é g o r i e d ’ é v é nements ” + eventCateg + ” inconnue du m
é diateur ”) ;
78 }
79 },
80
81 /* *
82 * 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 callbacks
correspondants .
83 * @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
84 * @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 é . . . )
85 */
86 p u b l i s h : function ( eventCateg , c o n t e x t A rg ) {
87 var i ;
88 i f ( m _ s u b s c r i p t i o n L i s t s . hasOwnProperty ( eventCateg ) ) {
89 f or ( var 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 ) {
90 // On a p p e l l e l e c a l l b a k a v e c son
91 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 t e x t A r g ) ;
92 }
93 } else {
94 throw new E r r o r ( ” Cat é g o r i e d ’ é v é nements ” + eventCateg + ” inconnue du m
é diateur ”) ;
95 }
96 },
97
98 // 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 .
99 empty : function ( ) {
100 init () ;
101 }
102 };
103
89
Rémy Malgouyres, https://malgouyres.org Programmation JavaScript, Patterns, Web
104 return p u b l i c I n t e r f a c e M e d i a t o r ;
105 }() ] ) ;
90
Chapitre 5 : Exemple d’Application avec IHM
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 ( ” per s on n e / 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 pe r s o n n 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
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 ( ” per s on n e / 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 s o n n e .
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 i a t o r . p u b l i s h ( ” pe rs o n n 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 n n 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 . . . )
84 // du f o r m u l a i r e l o r s du s u b m i t
91
Rémy Malgouyres, https://malgouyres.org Programmation JavaScript, Patterns, Web
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 i a t o r . p u b l i s h ( ” pe rs o n n 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 per s onn 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
pe rs o 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 o n n 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 i a t o r . p u b l i s h ( ” pe rs o n n 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
index
92
Chapitre 5 : Exemple d’Application avec IHM
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 fo r ( 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 ( ” per s on n e / 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 ( ” per s on n e / d e t a i l s R e b u i l t ” ,
registerButtonClickEvents ) ;
153 }]) ;
93
Rémy Malgouyres, https://malgouyres.org Programmation JavaScript, Patterns, Web
94
Chapitre 5 : Exemple d’Application avec IHM
95
Rémy Malgouyres, https://malgouyres.org Programmation JavaScript, Patterns, Web
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 i a t o r . p u b l i s h ( ” pe rs o n n 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 n n e s é
lectionn ée .
65 * @param { pe r so nne } c o n t e x t A r g . pe rs o n n e n o u v e l l e p e r s o n n e 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 n t e x t A 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 s o n n e 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 t e 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 ( ” per s on n e / 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 n n 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 n n e s é
lectionn ée .
86 * @param { pe r so nne } c o n t e x t A r g . pe rs o n n e n o u v e l l e p e r s o n n e 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 t A r g ) {
89 s e l e c t P e r s o n n e ( co n t ex 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 n n e
94 myApp . g u i . m ed i a t o r . s u b s c r i b e ( ” per s on n e / 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 n n e
96 myApp . g u i . m ed i a t o r . s u b s c r i b e ( ” per s on n e / 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 s o n n e .
98 myApp . g u i . m ed i a t o r . s u b s c r i b e ( ” per s on n e / 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 }() ] ) ;
96
Chapitre 5 : Exemple d’Application avec IHM
97
Rémy Malgouyres, https://malgouyres.org Programmation JavaScript, Patterns, Web
98
Chapitre 5 : Exemple d’Application avec IHM
99
Rémy Malgouyres, https://malgouyres.org Programmation JavaScript, Patterns, Web
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 attributeName ,
16 inputId ;
17 // On r é c u p è r e l e s a t t r i b u t s du f o r m u l a i r e dans une n o u v e l l e i n s t a n c e
18 var changedPersonne = 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 ) ;
19 // 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 )
20 f o r ( var j =0 ; j< myApp . m e t i e r . p e r s o n n e . g e t A t t r i b u t e L i s t ( ) . l e n g t h ; ++j ) {
21 var attributeName = myApp . m e t i e r . p e r s o n n e . g e t A t t r i b u t e L i s t ( ) [ j ] ;
22 i f ( attributeName != ” i d ” ) {
23 // c a l c u l de l ’ ID de l ’ i n p u t
24 var i n p u t I d = myApp . g u i . g e t I n p u t I d ( {
25 attributeName : attributeName ,
26 formId : ” modifierPersonneForm ”
27 }) ;
28 // 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 n n e
29 // 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 .
30 changedPersonne . s e t A t t r i b u t e ( attributeName ,
31 document . getElementById ( i n p u t I d ) . v a l u e
32 );
33
34 }
35 }
36 // Seulement s ’ i l n ’ y a pas d ’ e r r e u r ( f i l t r a g e s t r i c t c ô t é c l i e n t )
37 i f ( ! changedPersonne . h a s E r r o r ( ) ) {
38 fo r ( var j =0 ; j< myApp . m e t i e r . p e r s o n n e . g e t A t t r i b u t e L i s t ( ) . l e n g t h ; ++j ) {
39 var attributeName = myApp . m e t i e r . p e r s o n n e . g e t A t t r i b u t e L i s t ( ) [ j ] ;
40 i f ( attributeName != ” i d ” ) {
41 myApp . modele . s e l e c t e d P e r s o n n e . s e t A t t r i b u t e ( attributeName ,
42 changedPersonne . g e t A t t r i b u t e (
attributeName ) ) ;
43 }
44 }
45 // 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 p e r s o n n e
46 myApp . g u i . m e d i a t o r . p u b l i s h ( ” pe rs o n n e / changed ” , {
47 p e r s o n n e : myApp . modele .
selectedPersonne
48 }) ;
49 }
50 };
51
52 // 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
53 myApp . g u i . m ed i a t o r . s u b s c r i b e ( ” per s on n e / u p d a t e ” , updateModel ) ;
54 }() ] ) ;
100
Chapitre 5 : Exemple d’Application avec IHM
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 pe r s o n n 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 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 ( ) {
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 attributeName ,
14 inputId ;
15
16 // Ré cup é r a t i o n d e s donn é e s du f o r m u l a i r e dans une n o u v e l l e i n s t a n c e
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 // 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 )
19 f o r ( var j =0 ; j< myApp . m e t i e r . p e r s o n n e . g e t A t t r i b u t e L i s t ( ) . l e n g t h ; ++j ) {
20 var attributeName = myApp . m e t i e r . p e r s o n n e . g e t A t t r i b u t e L i s t ( ) [ j ] ;
21 i f ( attributeName != ” i d ” ) {
22 // c a l c u l de l ’ ID de l ’ i n p u t
23 var i n p u t I d = myApp . g u i . g e t I n p u t I d ( {
24 attributeName : attributeName ,
25 formId : ” ajouterPersonneForm ”
26 }) ;
27 // 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 n n e
28 // 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 .
29 n o u v e l l e P e r s o n n e . s e t A t t r i b u t e ( attributeName ,
30 document . getElementById ( i n p u t I d ) . v a l u e
31 );
32
33 }
34 }
35 // Seulement s ’ i l n ’ y a pas d ’ e r r e u r ( f i l t r a g e s t r i c t c ô t é c l i e n t )
36 i f ( ! nouvellePersonne . hasError () ) {
37 // Ajout de l a Personne au modèle
38 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 ) ;
39 // Provoquer l a s é l e c t i o n de l a n o u v e l l e pe r s o n n e ( e t par s u i t e l a mise à
j o u r de l a vue )
40 myApp . g u i . m e d i a t o r . p u b l i s h ( ” pe rs o n n e / c r e a t e d ” , {
41 personne : nouvellePersonne
42 }) ;
43 }
44 };
45
46 // 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
47 myApp . g u i . m ed i a t o r . s u b s c r i b e ( ” per s on n e / c r e a t e ” , updateModel ) ;
48
49 } ( ) ] ) ;
101
Rémy Malgouyres, https://malgouyres.org Programmation JavaScript, Patterns, Web
102
Chapitre 5 : Exemple d’Application avec IHM
103
Rémy Malgouyres, https://malgouyres.org Programmation JavaScript, Patterns, Web
112 }) ;
113
114 // ///////////////////////////////////////////////////
115 // 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
116 // t r y {
117 // Exé c u t i o n de l a mé t h o d e mainFunction
118 myApp . mainFunction ( ) ;
119 // } c a t c h ( e ) {
120 // a l e r t ( e . message ) ;
121 // }
122 </s c r i p t>
123 </body>
124 </html>
104
Chapitre 5 : Exemple d’Application avec IHM
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 n n 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 o n n 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 i a 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 s o n n e 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
pe rs o 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 o r ( var i =0 ; i < myApp . modele . s e l e c t e d P e r s o n n e . ge tN bA dr 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 A t t r i b u t e ( ’ 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 A t t r i b u t e ( ’ 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 }
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 .
105
Rémy Malgouyres, https://malgouyres.org Programmation JavaScript, Patterns, Web
106
Chapitre 5 : Exemple d’Application avec IHM
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).
Code Source 5.13 : /ihm-demo/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 rso 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 s o n n e 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 A t t r i b u t e ( ”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 jo ut erA dresseF or 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 ( co n te x t A r 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 ut e rA dre sse Form ” ) . 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 ut e rA dre sse Form ” ) . 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 ed 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
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.
107
Rémy Malgouyres, https://malgouyres.org Programmation JavaScript, Patterns, Web
108
Chapitre 5 : Exemple d’Application avec IHM
109
Rémy Malgouyres, https://malgouyres.org Programmation JavaScript, Patterns, Web
23 // c a l c u l de l ’ ID de l ’ i n p u t
24 var i n p u t I d = myApp . g u i . g e t I n p u t I d ( {
25 attributeName : attributeName ,
26 formId : ” ajou terA d res s e Fo r m ”
27 }) ;
28 // 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
29 // 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 .
30 n o u v e l l e A d r e s s e . s e t A t t r i b u t e ( attributeName ,
31 document . getElementById ( i n p u t I d ) . v a l u e
32 );
33 }
34 }
35 i f ( ! nouvelleAdresse . hasError () ) {
36 // Provoquer l a mise à j o u r de l a vue ( panneau d e s d é t a i l s )
37 myApp . g u i . m e d i a t o r . p u b l i s h ( ” pe rs o n n e / d e t a i l s C h a n g e d ” , {
38 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
39 }) ;
40 // Provoquer l a r e q u ê t e AJAX pour l ’ i m p l é m e n t a t i o n de l a p e r s i s t a n c e
41 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 ” , {
42 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 ,
43 adresse : nouvelleAdresse
44 }) ;
45 } else {
46 myApp . modele . s e l e c t e d P e r s o n n e . d e l e t e A d r e s s e ( n o u v e l l e A d r e s s e ) ;
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 ed 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 }() ] ) ;
110
Chapitre 5 : Exemple d’Application avec IHM
111
Rémy Malgouyres, https://malgouyres.org Programmation JavaScript, Patterns, Web
68 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 ” , {
69 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 ,
70 adresse : adresseEnQuestion
71 }) ;
72 }
73 };
74 // 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
75 myApp . g u i . m ed 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 ) ;
76 }() ] ) ;
112
Chapitre 6
On peut, par exemple, générer un tel tableau sur un serveur en PHP par le code suivant :
Code Source 6.2 : Génération et sortie du code JSON en PHP
1 < ?php
2 $myArray = array ( ” 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 ” => array ( ”PDF” , ” P o s t s c r i p t ” , ”HTML” , ” ePub ” ) ) ;
6 // Header HTTP sp é c i f i q u e :
7 header ( ’ c o n t e n t −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 ’ ) ;
8 echo json_encode ( $myArray ) ;
113
Rémy Malgouyres, https://malgouyres.org Programmation JavaScript, Patterns, Web
9 ?>
• 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.
114
Chapitre 6 : Requêtes Asynchrones et API Restful
115
Rémy Malgouyres, https://malgouyres.org Programmation JavaScript, Patterns, Web
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 .
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 ’ exemple
...) .
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 ’ une 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 er s on n 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 : ’ post ’ , // 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
116
Chapitre 6 : Requêtes Asynchrones et API Restful
• Opération Read. De lire toutes les ressources (ici d’une table de base de données).
Exemple : Lire toutes les personnes de la table Personne, avec une collection d’adresses
pour chaque personne (résultat d’une jointure en SQL qui correspond à un agrégat sur
les objets métiers).
117
Rémy Malgouyres, https://malgouyres.org Programmation JavaScript, Patterns, Web
agrégat).
Exemple 1 : Lire l’adresse d’identifiant unique (clé primaire de la table Adresse égaler à
af49bc053de73a0.
Exemple 2 : Lire toutes les adresses de la personne d’identifiant unique bd56bc053de12b3.
Exemple 3 : Lire toutes les personnes de la table Personne qui ont une adresse avec le
code postal commençant par les deux chiffre 63.
• Opération Update. De mettre à jour une ressource (ici une ligne d’une table de base
de données) identifiée de manière unique (par un identifiant unique), avec des données
(partielles ou complètes) à modifier.
Exemple : Modifier le code postal d’une adresse d’identifiant unique égal à af49bc053de73a0.
• Opération Delete. De détruire une ressource (ici une ligne d’une table de base de don-
nées) identifiée de manière unique (par un identifiant unique) ;
Exemple : Détruire la personne d’identifiant unique bd56bc053de12b3, ainsi que (s’agis-
sant d’une composition) toutes ses adresses de la table adresse (utilisation d’une clé
étrangère).
En utilisant cette interface (service web), l’application côté client pourra accéder à la couche
persistance du serveur.
Nous voyons aussi comment implémenter ces opérations sur le serveur en spécifiant les iden-
tifiants et les actions au moyen d’une URI (Universal Ressource Identifier) et des verbes (aussi
appelés méthodes, GET, PUT, POST, PATCH ou DELETE du protocole HTTP (norme RFC 2616
puis RFC 7230).
118
Chapitre 6 : Requêtes Asynchrones et API Restful
18 },
19 405 : function ( ) {
20 a l e r t ( ” Method Not Allowed ” ) ;
21 },
22 422 : function ( ) {
23 a l e r t ( ” U n p r o c e s s a b l e E n t i t y : A t t r i b u t i n c o r r e c t ?” ) ;
24 },
25 500 : function ( ) {
26 a l e r t ( ” I n t e r n a l S e r v e r Error ” ) ;
27 }
28 }]) ;
119
Rémy Malgouyres, https://malgouyres.org Programmation JavaScript, Patterns, Web
35 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 ( {
36 id : adressesData [ keyAdresse ] [ ” id ” ] ,
37 numeroRue : a d r e s s e s D a t a [ k e y A d r e s s e ] [ ”numeroRue” ] ,
38 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 ” ] ,
39 complementAddr : a d r e s s e s D a t a [ k e y A d r e s s e ] [ ” complementAddr ” ] ,
40 codePostal : adressesData [ keyAdresse ] [ ” codePostal ” ] ,
41 v i l l e : adressesData [ keyAdresse ] [ ” v i l l e ” ] ,
42 pays : a d r e s s e s D a t a [ k e y A d r e s s e ] [ ” pays ” ]
43 }) ;
44 newPersonne . addAdresse ( a d r e s s e I n s t a n c e ) ;
45 }
46 }
47 myApp . modele . p e r s o n n e s . push (newPersonne ) ; // a j o u t dans l e modèle
48 }
49 }
50 } else {
51 a l e r t ( ” I l y a un o b j e t \” e r r o r \” non n u l l ” ) ;
52 }
53 };
54
55 /* *
56 * 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 ,
57 * 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 .
58 * 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 ) .
59 */
60 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 ) {
61
62 // Personne s é l e c t i o n n é e par d é f a u t
63 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 ] ;
64
65 // 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
66 $ ( ”#l i s t e P e r s o n n e s ” ) . empty ( ) ;
67 $ ( ”#v u e D e t a i l ” ) . empty ( ) ;
68 $ ( ”#ajouterPersonneForm ” ) . empty ( ) ;
69 $ ( ”#modifierPersonneForm ” ) . empty ( ) ;
70 $ ( ”#aj o ut e rA dre sse Form ” ) . empty ( ) ;
71 $ ( ”#modifierAdresseForm ” ) . empty ( ) ;
72
73 // Provoquer l e pr e mier a f f i c h a g e de l a vue :
74 myApp . g u i . m e d i a t o r . p u b l i s h ( ” per s on n e / changed ” , {
75 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
76 }) ;
77
78 // 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
79 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 ( ) ;
80 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 ( ) ;
81 };
82
83 /* *
84 * C a l l b a c k a p p e l é l o r s de l ’ é v é nement ” p ers o n n e / rea d ” du mé d i a t o r .
85 * 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
86 * pour r e c o n s t r u i r e l e modèle de donn é e s .
87 */
88 var r e a d A l l P e r s o n n e = function ( ) {
89 // r e q u ê t e AJAX g e t cod é en JSON
90 var j q x h r = $ . a j a x ( {
120
Chapitre 6 : Requêtes Asynchrones et API Restful
121
Rémy Malgouyres, https://malgouyres.org Programmation JavaScript, Patterns, Web
122
Chapitre 6 : Requêtes Asynchrones et API Restful
123
Rémy Malgouyres, https://malgouyres.org Programmation JavaScript, Patterns, Web
15 i f ( r e t r i e v e d D a t a [ ’ e r r o r ’ ] . hasOwnProperty ( key ) ) {
16 concatErrorMsg += key + ” : ” + r e t r i e v e d D a t a [ ’ e r r o r ’ ] [ key ] + ” \n” ;
17 }
18 }
19 a l e r t ( concatErrorMsg ) ;
20 }
21 };
22
23 /* *
24 * C a l l b a c k a p p e l é l o r s de l ’ é v é nement ” p ers o n n e / rea d ” du mé d i a t o r .
25 * 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
26 * pour r e c o n s t r u i r e l e modèle de donn é e s .
27 */
28 var c r e a t e P e r s o n n e = function ( c o n t e x t A r g ) {
29
30 // r e q u ê t e AJAX g e t cod é en JSON
31 var j q x h r = $ . a j a x ( {
32 dataType : ” j s o n ” , // On e n v o i e l e s donn é e s l a p e r s o n n e cod é e en JSON
33 // L ’URI c o m p l è t e i n c l u s l ’ ID de l a r e s s o u r c e à c r é e r
34 u r l : ” h t t p :// p r o g j s / e x e m p l e s / a p i R e s t f u l / p e r s o n n e / ”
35 + c o n t e x t A rg . p e r s o n n e . g e t A t t r i b u t e ( ” i d ” ) ,
36 method : ’ p o s t ’ , // Verbe HTTP
37 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 ’ ,
38 // donn é e s à t r a n s m e t t r e au s e r v e u r
39 data : {
40 p e r s o n n e : { // A t t r i b u t s de l a p er s o n n e
41 nom : c o n t e x tA r g . p e r s o n n e . g e t A t t r i b u t e ( ”nom” )
42 }
43 },
44 // 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
45 success : ajaxCallbackSuccess ,
46 // O b j e t d é f i n i s s a n t l e s c a l l b a c k s d ’ e r r e u r s a v e c c o d e s du s e r v e u r
47 s t a t u s C o d e : myApp . p e r s i s t a n c e . s t a t u s C o d e O b j e c t
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 mise à j o u r de l a pe r s o n n e
51 myApp . g u i . m ed i a t o r . s u b s c r i b e ( ” per s on n e / c r e a t e d ” , c r e a t e P e r s o n n e ) ;
52 }() ] ) ;
124
Chapitre 6 : Requêtes Asynchrones et API Restful
15 i f ( r e t r i e v e d D a t a [ ’ e r r o r ’ ] . hasOwnProperty ( key ) ) {
16 concatErrorMsg += key + ” : ” + r e t r i e v e d D a t a [ ’ e r r o r ’ ] [ key ] + ” \n” ;
17 }
18 }
19 a l e r t ( concatErrorMsg ) ;
20 }
21 };
22
23 /* *
24 * C a l l b a c k a p p e l é l o r s de l ’ é v é nement ” p ers o n n e / rea d ” du mé d i a t o r .
25 * 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
26 * pour r e c o n s t r u i r e l e modèle de donn é e s .
27 */
28 var updatePersonne = function ( c o n t e x t A r g ) {
29
30 // r e q u ê t e AJAX g e t cod é en JSON
31 var j q x h r = $ . a j a x ( {
32 dataType : ” j s o n ” , // On e n v o i e l e s donn é e s l a p e r s o n n e cod é e en JSON
33 // L ’URI c o m p l è t e i n c l u s l ’ ID de l a r e s s o u r c e à c r é e r
34 u r l : ” h t t p :// p r o g j s / e x e m p l e s / a p i R e s t f u l / p e r s o n n e / ”
35 + c o n t e x t A rg . p e r s o n n e . g e t A t t r i b u t e ( ” i d ” ) ,
36 method : ’ p u t ’ , // Verbe HTTP
37 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 ’ ,
38 // donn é e s à t r a n s m e t t r e au s e r v e u r
39 data : {
40 p e r s o n n e : { // A t t r i b u t s de l a p er s o n n e
41 nom : c o n t e x tA r g . p e r s o n n e . g e t A t t r i b u t e ( ”nom” )
42 }
43 },
44 // 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
45 success : ajaxCallbackSuccess ,
46 // O b j e t d é f i n i s s a n t l e s c a l l b a c k s d ’ e r r e u r s a v e c c o d e s du s e r v e u r
47 s t a t u s C o d e : myApp . p e r s i s t a n c e . s t a t u s C o d e O b j e c t
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 mise à j o u r de l a pe r s o n n e
51 myApp . g u i . m ed i a t o r . s u b s c r i b e ( ” per s on n e / changed ” , updatePersonne ) ;
52 }() ] ) ;
125
Rémy Malgouyres, https://malgouyres.org Programmation JavaScript, Patterns, Web
126
Chapitre 6 : Requêtes Asynchrones et API Restful
127
Rémy Malgouyres, https://malgouyres.org Programmation JavaScript, Patterns, Web
128
Chapitre 6 : Requêtes Asynchrones et API Restful
20 }
21 };
22
23 /* *
24 * C a l l b a c k a p p e l é l o r s de l ’ é v é nement ” p ers o n n e / rea d ” du mé d i a t o r .
25 * 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
26 * pour r e c o n s t r u i r e l e modèle de donn é e s .
27 */
28 var d e l e t e A d r e s s e = function ( c o n t e x t A r g ) {
29
30 // r e q u ê t e AJAX g e t cod é en JSON
31 var j q x h r = $ . a j a x ( {
32 dataType : ” j s o n ” , // On e n v o i e l e s donn é e s l a p e r s o n n e cod é e en JSON
33 // L ’URI c o m p l è t e i n c l u s l ’ ID de l a r e s s o u r c e à s u p p r i m e r
34 u r l : ” h t t p :// p r o g j s / e x e m p l e s / a p i R e s t f u l / a d r e s s e /”
35 + c o nt e x tA r g . a d r e s s e . g e t A t t r i b u t e ( ” i d ” ) ,
36 method : ’ d e l e t e ’ , // Verbe HTTP
37 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 ’ ,
38 // donn é e s à t r a n s m e t t r e au s e r v e u r
39 data : {
40 // O b j e t v i d e ( l e paramètre ID e s t sp é c i f i é dans l ’URI)
41 },
42 // 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
43 success : ajaxCallbackSuccess ,
44 // O b j e t d é f i n i s s a n t l e s c a l l b a c k s d ’ e r r e u r s a v e c c o d e s du s e r v e u r
45 s t a t u s C o d e : myApp . p e r s i s t a n c e . s t a t u s C o d e O b j e c t
46 }) ;
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 de mise à j o u r de l a pe r s o n n e
50 myApp . g u i . m ed 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 ) ;
51 }() ] ) ;
129
Annexe A
130
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>
131
Rémy Malgouyres, https://malgouyres.org Programmation JavaScript, Patterns, Web
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>
132
Annexe B
Programmation Événementielle en
JavaScript
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é.
133
Rémy Malgouyres, https://malgouyres.org Programmation JavaScript, Patterns, Web
7 body {
8 f o n t −f a m i l y : ”Comic Sans MS” ;
9 f o n t −s i z e : 120% ;
10 }
11 h1{
12 margin : 0 auto ;
13 t e x t −a l i g n : c e n t e r ;
14 }
15 p . popupDetails {
16 background−c o l o r : y e l l o w ;
17 p o s i t i o n : r e l a t i v e ; /* pour p o s i t i o n 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 d i s p l a y : none ;
22 }
23 p . p o p u p D e t a i l s :hover span {
24 position : absolute ;
25 l e f t : 200 px ;
26 top : −30 ;
27 min−width : 500 px ;
28 background−c o l o r : b l a c k ;
29 c o l o r : white ;
30 border −r a d i u s : 20 px ;
31 padding : 10 px ;
32 display : block ;
33 }
34 </ s t y l 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 use amé r i c a i n e .< br/>
44 ( s o u r c e  ; : 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 −−>
134
Chapitre B : Programmation Événementielle en JavaScript
1. Événements souris
2. Événements clavier
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())
135
Rémy Malgouyres, https://malgouyres.org Programmation JavaScript, Patterns, Web
136
Chapitre B : Programmation Événementielle en JavaScript
11 </p>
12 <p>
13 <s e l e c t name=” annee ” id=” annee ” pattern=” ( p r e m i e r e ) | ( deuxieme ) ”
onchange= ’ anneeChange ( ) ; ’>
14 <option value=” c h o i s i s s e z ” selected disabled>−− c h o i s i s s e z −−</option>
15 <option value=” p r e m i e r e ”>Prem ière ann é e</option>
16 <option value=” deuxième ”>Deuxième ann é e</option>
17 </s e l e c t>
18 </p>
19 <div id=” 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 ” value=”−− OK −−” />
24 </p>
25 </form>
26 <s c r i p t>
27 function anneeChange ( ) {
28 var pa ra gr a p h e = 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 p a r a g ra p h e . innerHTML=document . getElementById ( ” annee ” ) . value+” ann é e .<br />” ;
30 i f ( document . getElementById ( ” annee ” ) . value == ” deuxième ” ) {
31 par a g r 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 ” id=” o r i e n t a t i o n ”>’
33 +’<option value=”LP”>LP</option>’
34 +’<option value=” master ”>master</option>’
35 +”<option value= \” i n g e \”>E c o l e d ’ i n g é</option>”
36 +’<option value=” b o u l o t ”>Boulot</option>’
37 +’<option value=” 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>
137
Rémy Malgouyres, https://malgouyres.org Programmation JavaScript, Patterns, Web
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 é t e rm i n é ” ;
10 $annee = ( i s s e t ($_POST [ ” annee ” ] ) ) ? $_POST [ ” annee ” ] : ”ann é e i n d é temin é e ” ;
11 echo ”Nom : ” . $nom . ”<b r/>” ;
12 echo ”Anné e : ” . $annee . ”<b r/>” ;
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>
138
Annexe C
139
Rémy Malgouyres, https://malgouyres.org Programmation JavaScript, Patterns, Web
20 </body>
21 </html>
140
Chapitre C : Gestion des fenêtres
141
Annexe D
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.
142
Chapitre D : Document Object Model (DOM)
13 </html>
Document
<html>
<head> <body>
"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.
143
Rémy Malgouyres, https://malgouyres.org Programmation JavaScript, Patterns, Web
12 </s t y l 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 class= ” 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 −radius ” , ” 20 px ” ) ;
33 </s c r i p t>
34 </body>
144
Chapitre D : Document Object Model (DOM)
7 <s t y l e>
8 p {
9 padding : 10 px 0 ;
10 }
11 </s t y l 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 p a r a g r a p h e 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>
145
Rémy Malgouyres, https://malgouyres.org Programmation JavaScript, Patterns, Web
7 <s t y l e>
8 p . myClass {
9 background−color : #ddd ;
10 padding : 10 px ;
11 }
12 </s t y l 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 class= ” 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>
146
Chapitre D : Document Object Model (DOM)
1 <!doctype html>
2 <html lang=” f r ”>
3 <head>
4 <meta charset=” utf−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 src=” . /jquery−1 . 1 0 . 2 . j s ”></s c r i p t>
7 <s t y l e>
8 p {
9 background−color : #ddd ;
10 padding : 10 px ;
11 }
12 div . myClass {
13 font−weight : b o l d e r ;
14 padding : 10 px ;
15 border −style : dashed ;
16 }
17 em {
18 font −variant : small−caps ;
19 font−s i z e : 120% ;
20 }
21 button {
22 margin : 10 px 0 ;
23 }
24 </s t y l e>
25 </head>
26
27 <body>
28 <h1>Év é nement de c l i c k</h1>
29 <div>
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>
147
Rémy Malgouyres, https://malgouyres.org Programmation JavaScript, Patterns, Web
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 class= ” myClass ”>’ + $ ( t h i s ) . html ( )
+ ”</div>” ) ;
45 }) ;
46 }) ;
47 </s c r i p t>
48 </body>
148
Chapitre D : Document Object Model (DOM)
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 src=” . /jquery−1 . 1 0 . 2 . j s ”></s c r i p t>
10
11 <p id=” 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 fo r ( 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 , value ) {
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 , value ) {
33 outHTML += ” t a b [ ”+key +” ] = ”+value+”<br />” ;
34 }) ;
35 $ ( ”#o u t p u t ” ) . append ( outHTML ) ;
36 </s c r i p t>
37 </body>
38 </html>
149