Bonjour. Dans cette séquence, vous allez voir la
puissance de Seaside grâce à la composition de composants.
En fait, on a défini des composants qui sont
réutilisables et qui encapsulent de l'état, et maintenant
on va voir comment est-ce qu'on est capable de composer
ces composants en vue de construire des applications complexes.
Une application, c'est un composant racine, et puis on
profite du debuggage, du live debugging des applications.
On va revenir sur 3 mécanismes importants pour composer
des composants en Seaside. Le premier, l'agrégation de composants.
Je vous rappelle qu'on avait défini 2 Counter, un Counter
normal qui ressemblait à ça ici et puis un Counter TwitterCounter, ici.
Comment est-ce que je pourrais maintenant agréger un
composant au Counter en vue de construire une application multiCounter?
En fait, je voudrais afficher plein de Counter sur une
page et puis quand je clique sur ce + là par exemple, que
ça incrémente la valeur de ce Counter et pas d'un autre.
Donc, agréger comme ça plein de composants sur une même page facilement.
Comment est-ce qu'on fait en Seaside?
C'est extrêmement simple.
Je vais définir une sous classe de composants, toujours
pareil, qui s'appelle WAMultiCounter.
Une variable d'instances, Counter, qui va définir une collection de Counter.
Dans la méthode initialize, je vais créer une collection de 5 Counter ici.
Et puis, je vais avoir la méthode renderContentOn ici où
je vais parcourir ma collection de Counter avec un do, et
je vais demander à l'objet HTML de rendre chacun des
Counter, donc j'utilise une méthode particulière ici qui est render.
Cette méthode render de l'objet HTML permet de
demander à un composant de se rendre, de se dessiner, en HTML.
Et on a une méthode importante ici qui s'appelle
children, c'est-à-dire qu'un composant, lorsqu'il
encapsule d'autres composants et qu'il leur demande de se
rendre dans sa méthode renderContentOn, il doit les déclarer.
Et pour les déclarer il doit rendre une collection de
composants dans sa méthode children, qui contient tous
les composants qu'il va rendre, tous ses enfants en fait.
Ici, je rends bien la collection counter.
C'est une méthode importante à définir.
Les règles de base pour agréger des composants, pour
composer des composants, c'est facile.
Un composant va stocker ces sous-composants dans une
variable d'instances, dans notre exemple c'était counters.
Ensuite, il va envoyer le message render
dans sa méthode render content on aux paramètres HTML en
demandant à chacun de ses enfants de se rendre.
Et puis, il va redéfinir la méthode children pour
déclarer l'ensemble de ces sous- composants.
Il y a toujours ces 3 volets-là.
On peut aussi agréger des sous-composants différents, on
n'est pas obligé d'agréger des composants du même type.
Là, je n'avais agrégé que des Counter et maintenant on va
avoir un composant MyApp.
Dans la méthode initialize ici, c'est une collection,
sauf que dans cette collection de composants j'ai mis l'application
greeter qu'on avait mise dans une séquence précédente qu'on
avait vue, un TwitterCounter et un Counter, donc 3 composants.
Ma méthode children rend bien tous les children, tous les
sous-composants de ce composant-là MyApp.
Et dans renderContentOn, je vais bien parcourir l'ensemble
de mes enfants et demander à ce qu'ils se rendent.
Donc faire HTML render each, je vais faire HTML render du
greeter, du TwitterCounter et du Counter.
Voyons ce que ça donne.
Ici on a bien le composant greeter qui s'est affiché sur
la page Web, on a le Twittercounter qui s'est affiché ici
et on a le Counter normal qui s'est affiché ici.
On a bien composé des composants et ils fonctionnent tous indépendamment.
Si je clique sur les +, les say hello et caetera, les
composants fonctionnent parfaitement.
Maintenant si on veut aller encore un petit cran plus
loin, on ne voudrait pas afficher tous les composants d'un
coup sur la page Web, on voudrait qu'il n'y en ait qu'un
qui s'affiche à l'instant T et afficher un menu par
exemple pour sectionner quels sous-composants on veut afficher.
Typiquement, je voudrais afficher juste le greeter et
quand je clique sur TwitterCounter ici, je ne vais
afficher que le TwitterCounter dessous.
Comment faire cette application ?
C'est facile, je vais rajouter une variable d'instances
dans mon application MyApp qui va s'appeler le composant
sélectionné, quel est l'enfant qui a été sélectionné, par
défaut je vais l'initialiser au premier sous-composant.
Dans ma méthode renderContentOn ici, je l'ai modifié.
Je vais afficher un menu qui va me donner la possibilité
de sélectionner quel sous-composant je vais afficher.
Et puis, je vais faire HTML render mais seulement du
sous-composant que je veux afficher tout simplement.
Et dans le menu, je vais générer ici une liste en
ordonnées, je vais parcourir l'ensemble de mes
sous-composants avec un index, ici i.
Et je vais générer un élément de liste pour chacun des enfants.
Donc ici je vais générer une ancre, c'est un lien
cliquable et quand je clique sur ce lien ça va déclencher
le callBack, l'exécution de ce bloc ici donc on
va dire que le composant sélectionné par l'utilisateur, c'est
l'enfant numéro, donc self children, je rappelle que c'était
une collection, at i.
Et i ici, ce n'est ni plus ni moins que le
numéro de l'élément dans la collection children.
Il est extrêmement facile de pouvoir parcourir l'ensemble
des sous-composants et de générer spécifiquement ce qu'on
veut, de contrôler complètement qui doit s'afficher et
qui ne doit pas s'afficher.
On va avoir un deuxième mécanisme de composition qui est le call answer.
On a vu la composition de composants avec les
sous-composants et maintenant on va voir le mécanisme call answer.
Dans le code du composant A, on va écrire quelque chose
qui ressemble à ce code ici, on va dire "Composant A
appelle composant B, call composant B.
" Le composant B va masquer le composant A sur la page
Web, il va réaliser un traitement.
Et à un moment donné, le composant B va dire "J'ai fini
mon traitement donc je vais faire answer et je vais rendre un résultat.
" Le résultat c'est une étoile.
Ce résultat va être stocké dans X à la place du call
composant B.
Et maintenant, le composant A va se réafficher sur la page Web.
Et le composant A va pouvoir utiliser ce résultat pour faire quelque chose.
Je vous montre un exemple.
Ici, on a un premier composant qui était le Counter, on
lui a rajouté un bouton ici, set value, et on imagine que
set value ça offre la possibilité à l'utilisateur de
rentrer une nouvelle valeur pour le Counter.
Quand on clique sur ce bouton set value, il y a un
nouveau composant ici qui est affiché, c'était un peu
comme le composant gritter qu'on avait vu avant, on peut
rentrer une nouvelle valeur pour le Counter, cliquer sur
le bouton OK, et quand je clique sur le bouton OK ça
revient à notre composant compteur mais avec la valeur
ici qui avait été rentrée par l'utilisateur au début.
On a bien un enchaînement de plusieurs composants.
Comment est-ce que c'est implémenté ?
On a notre composant TwitterCounter qui a sa méthode renderContentOn.
Dans sa méthode renderContentOn, on va rajouter un
bouton, un Tbsbutton, ce bouton s'appelle set value ici.
Quand on clique sur ce bouton c'est ce callBack qui va
être exécuté, donc c'est la méthode set count to user value.
SetCountToUserValue est défini ici.
On va préparer ici une boîte de dialogue.
On va utiliser un autre composant qui est offert par
Seaside qui est une boîte de dialogue qu'on va paramétrer ici.
On l'instancie, on la paramètre avec entrer une nouvelle
valeur pour le compteur, par défaut c'est égal à 0.
Et puis, il y aura un bouton OK.
L'élément extrêmement intéressant, c'est cette ligne-là ici.
On va dire "Composant
courant, donc self, c'est le TwitterCounter, appelle
la boîte de dialogue qu'on vient de créer et rends-moi le
résultat", et le résultat ça sera la nouvelle valeur du Counter.
Et ensuite quand on a fini ici, on va dire "Count, la
valeur du counter, prends cette nouvelle valeur qui a été
entrée par l'utilisateur convertie sous la forme d'un
nombre", tout simplement.
En interne, on peut regarder comment fonctionne cette
boîte de dialogue WAInputDialog. En fait, c'est un
composant Seaside réutilisable tout à fait classique,
sauf qu'il a une particularité, il va utiliser la méthode
answer pour renvoyer un résultat.
En fait si on regarde sa méthode render content on à ce
composant-là, quand on clique sur son bouton OK, donc
ici son submitButton, il y a bien un callBack avec un
block, et dans son callBack il va faire self
answer value. Ça veut dire que ça
va renvoyer les résultats au composant qui avait fait un call sur lui.
Ça va vraiment revenir à l'endroit où le call avait été
fait et renvoyer le résultat.
On a vu le mécanisme call answer, maintenant on va voir
un dernier mécanisme de composition de composants qui est
celui des tâches, des tasks.
En fait c'est très simple, les tâches c'est comme des
composants, sauf qu'il n'y a pas de partie graphique,
donc il n'y aura pas de méthode renderContentOn, pas de génération de HTML.
L'idée, c'est vraiment de venir orchestrer, de venir
décrire comment des composants doivent s'exécuter dans le
temps: d'abord ce composant-là fera ça et ensuite
celui-là, et cetera, en utilisant des call answers cachés derrière.
On va définir une tâche qui s'appelle un adder et puis
toutes les tâches ont une méthode qui s'appelle go.
Ici par exemple dans cette tâche, on va demander à l'utilisateur
de rentrer un nombre, donc self request number 1.
Ensuite, on va lui demander de rentrer un deuxième
nombre, self request number 2.
Et ensuite, on va l'informer d'une valeur qui est l'addition
de ces 2 nombres ici.
A la dernière ligne, on enregistre ce composant comme une
application Web classique pour pouvoir y accéder avec un navigateur.
Si on regarde en interne, la méthode request comment
est-ce qu'elle est implémentée ?
La méthode request in fine utilise en interne call
et answer. Si on revient à l'exemple précédent, on voit
bien qu'au moment où on a fait request ici à l'intérieur,
ça revient à appeler un autre composant et pas n'importe
lequel, le composant WAInputDialog, à afficher les
chaînes de caractères qui vont bien et puis ce composant
va rendre le résultat à celui qui l'avait appelé.
En l'occurrence qui est-ce qui l'avait appelé?
Notre composant adder.
Donc, il va bien récupérer une valeur dans value 1.
La même chose pour value 2.
Et ensuite, si on regarde dans le in form, comment est-ce
qu'il est implémenté ?
Lui aussi utilise un call answer mais sur un autre type
de composant qui est informDialog.
Ici on fait self callFormDialog; donc on va afficher une
chaîne des caractères à l'utilisateur avec un bouton OK
pour dire "OK, il a bien vu la chaîne de caractères.
"
Ce qui était important à retenir dans toutes ces formes
de compositions, c'est qu'on n'a jamais parlé de requêtes
http, d'URL, de découpage d'URL, de paramètres, on n'a
pas parlé de routage de requêtes.
On n'a pas non plus fixé des liens vers des pages
suivantes, et cetera, on a uniquement parlé de composants
qui ont de l'état, qu'on va pouvoir composer.
Il y a 3 formes de compositions: un composant peut
encapsuler d'autres composants, un composant peut appeler
un autre composant, et puis on peut définir des workflow,
des enchaînements de composants en Seaside, ce qui est extrêmement puissant.
Et tout ça avec la possibilité de le debugger en live.