V. Visualisation et écriture des commentaires▲
La page d'accueil étant maintenant créée, nous allons continuer notre travail en créant la page de détails des billets. C'est sur cette page que nous pouvons visualiser les commentaires, et nous y inclurons également un formulaire pour en poster de nouveaux.
V-A. Création de l'action show▲
Pour afficher le détail d'un billet, nous devons écrire une nouvelle méthode d'action dans notre contrôleur. Appelons-la show() :
public
static
void
show
(
Long id) {
Post post =
Post.findById
(
id);
render
(
post);
}
Comme nous le voyons, l'écriture de cette action est extrêmement simple. Nous déclarons en paramètre de la méthode un ID qui sera automatiquement récupéré depuis la requête HTTP. Ce paramètre peut être extrait soit du queryString, soit de l'URL directement, soit du corps de la requête.
Si nous essayons d'envoyer une valeur incorrecte pour le paramètre ID par HTTP, alors sa valeur sera mise à null, et Play ajoutera une erreur de validation au conteneur d'erreurs.
Cette action affichera le contenu du template /yabe/apps/view/Application/show.html :
#{extends 'main.html' /}
#{set title:post.title /}
#{display post:post, as:'full' /}
Le fait que nous ayons déjà écrit le tag display, ce template se révèle très simple à écrire !
V-B. Ajout de liens dans la page des détails▲
Dans notre tag display, nous avions laissé vide la section des liens (en utilisant #). Nous pouvons maintenant les faire pointer sur l'action Application.show. Avec Play, la construction de liens dans un template se réalise grâce à la notation @{...}. Cette syntaxe utilise de façon inversée le routeur pour déterminer l'URL qui doit être appelée pour une action spécifique.
Editons le fichier de tag /yabe/app/views/tags/display.html :
...
<h2 class
=
"post-title"
>
<a href
=
"@{Application.show(_post.id)}"
>
${_post.title}</a>
</h2>
...
Nous pouvons à présent rafraichir la page d'accueil et cliquer sur un billet pour l'afficher :
Voilà qui n'est pas mal du tout. Nous allons toutefois ajouter un lien pour revenir à la page d'accueil. Editons le fichier /yabe/app/views/main.html afin de compléter le lien du titre :
...
<div id
=
"title"
>
<span class
=
"about"
>
About this blog</span>
<h1><a href
=
"@{Application.index()}"
>
${blogTitle}</a></h1>
<h2>${blogBaseline}</h2>
</div>
...
Les visiteurs peuvent maintenant naviguer de la page d'accueil vers la page de détails du billet, et vice-versa.
V-C. Spécification d'une plus belle URL▲
Lorsque nous visualisons la page des détails d'un billet, l'URL ressemble à ceci :
.../application/show?id=1
Cela résulte du fait que Play a utilisé la route globale par défaut :
* /{controller}/{action} {controller}.{action}
Nous pouvons améliorer l'affichage des URL en spécifiant un chemin particulier pour l'action Application.show. Editons le fichier /yabe/conf/routes et ajoutons cette route à la fin :
GET /posts/{id} Application.show
De cette façon, le paramètre ID sera extrait directement de l'URL. Vous pouvez en savoir plus sur l'utilisation de l'URI dans la documentation de la syntaxe sur le fichier de routage.
Rafraichissons à nouveau notre page afin de nous assurer que les URL sont désormais correctement écrites.
V-D. Gérons la pagination▲
Pour faciliter la vie des visiteurs de notre blog, nous allons leur permettre de naviguer d'un billet à un autre. Nous améliorons ainsi notre classe Post afin de permettre de récupérer le billet précédent ainsi que le suivant :
public
Post previous
(
) {
return
Post.find
(
"postedAt < ? order by postedAt desc"
, postedAt).first
(
);
}
public
Post next
(
) {
return
Post.find
(
"postedAt > ? order by postedAt asc"
, postedAt).first
(
);
}
Nous appellerons ces méthodes à plusieurs reprises, et il serait bon des les optimiser. Toutefois, nous nous contenterons de cette version ici. Maintenant, il faut ajouter les liens de pagination en haut du template show.html, précédemment le tag #{display /} :
<ul id
=
"pagination"
>
#{if post.previous()}
<li id
=
"previous"
>
<a href
=
"@{Application.show(post.previous().id)}"
>
${post.previous().title}
</a>
</li>
#{/if}
#{if post.next()}
<li id
=
"next"
>
<a href
=
"@{Application.show(post.next().id)}"
>
${post.next().title}
</a>
</li>
#{/if}
</ul>
Voilà qui est bien mieux !
V-E. Ajout du formulaire de nouveau commentaire▲
Attaquons désormais le formulaire de saisie d'un nouveau commentaire. Commençons par ajouter une méthode action postComment() dans notre contrôleur :
public
static
void
postComment
(
Long postId, String author, String content) {
Post post =
Post.findById
(
postId);
post.addComment
(
author, content);
show
(
postId);
}
Comme on peut le voir, nous réutilisons la méthode addComment() que nous avions écrite dans un chapitre précédent. Occupons nous du code HTML dans le template show.html :
<h3>Post a comment</h3>
#{form @Application.postComment(post.id)}
<p>
<label for
=
"author"
>
Your name: </label>
<input type
=
"text"
name
=
"author"
id
=
"author"
/>
</p>
<p>
<label for
=
"content"
>
Your message: </label>
<textarea name
=
"content"
id
=
"content"
></textarea>
</p>
<p>
<input type
=
"submit"
value
=
"Submit your comment"
/>
</p>
#{/form}
Voilà ! Les visiteurs sont désormais capables de poster des commentaires sur nos billets.
V-F. Ajout de la validation▲
Actuellement, nous ne validons pas le contenu du formulaire avant la création du commentaire. Nous souhaitons rendre les deux champs (le nom et le message) obligatoires. Nous pouvons profiter de ce que Play met à notre disposition pour nous assurer que les différents paramètres HTTP sont correctement remplis. Modifions l'action postComment pour ajouter l'annotation de validation @Required :
public
static
void
postComment
(
Long postId, @Required
String author, @Required
String content) {
Post post =
Post.findById
(
postId);
if
(
validation.hasErrors
(
)) {
render
(
"Application/show.html"
, post);
}
post.addComment
(
author, content);
show
(
postId);
}
N'oublions pas d'importer le package play.data.validation.*.
Désormais, en cas d'erreur de validation, nous voulons réafficher la page de détails du billet. Nous devons donc modifier le code du formulaire pour afficher les erreurs :
<h3>Post a comment</h3>
#{form @Application.postComment(post.id)}
#{ifErrors}
<p class
=
"error"
>
All fields are required!
</p>
#{/ifErrors}
<p>
<label for
=
"author"
>
Your name: </label>
<input type
=
"text"
name
=
"author"
id
=
"author"
value
=
"${params.author}"
/>
</p>
<p>
<label for
=
"content"
>
Your message: </label>
<textarea name
=
"content"
id
=
"content"
>
${params.content}</textarea>
</p>
<p>
<input type
=
"submit"
value
=
"Submit your comment"
/>
</p>
#{/form}
Notez que nous réutilisons les paramètres postés afin de remplir les champs HTML.
Afin de rendre l'interface un peu plus agréable pour nos visiteurs, nous allons ajouter un peu de Javascript pour donner le focus automatiquement au formulaire en cas d'erreur. Ce script utilise la célèbre librairie jQuery, nous devons donc l'intégrer à notre application. Téléchargeons les deux composants de la librairie ici et ici. Nous devons ensuite les déposer dans le répertoire /yabe/public/javascripts, puis modifions le template main.html pour les inclure dans nos pages :
...
<script src
=
"@{'/public/javascripts/jquery-1.3.2.min.js'}"
></script>
<script src
=
"@{'/public/javascripts/jquery.tools.min.js'}"
></script>
</head>
Maintenant, il nous est possible d'ajouter ce petit script dans le template show.html (ajoutons-le à la fin de la page) :
<
script type=
"text/javascript"
charset=
"utf-8"
>
$(
function(
) {
// Expose the form
$(
'form'
).click
(
function(
) {
$(
'form'
).expose
({
api
:
true}
).load
(
);
}
);
// If there is an error, focus to form
if(
$(
'form .error'
).size
(
)) {
$(
'form'
).expose
({
api
:
true,
loadSpeed
:
0
}
).load
(
);
$(
'form input'
).get
(
0
).focus
(
);
}
}
);
</
script>
Notre formulaire d'ajout de commentaire a plutôt une bonne tête désormais ! Nous allons toutefois y ajouter deux petites choses.
Tout d'abord, nous souhaitons ajouter un message de confirmation lorsqu'un commentaire est posté avec succès. Pour cela, nous utilisons le scope flash qui nous autorise à passer un message de l'appel d'une action à une autre.
Modifions l'action postComment pour y ajouter un message de confirmation :
public
static
void
postComment
(
Long postId, @Required
String author, @Required
String content) {
Post post =
Post.findById
(
postId);
if
(
validation.hasErrors
(
)) {
render
(
"Application/show.html"
, post);
}
post.addComment
(
author, content);
flash.success
(
"Thanks for posting %s"
, author);
show
(
postId);
}
Affichons le message dans notre page show.html :
...
#{
if
flash.success}
<
p class
=
"success"
>
${
flash.success}</
p>
#{/
if
}
#{
display post:post, as:'full'
/}
...
La seconde chose que nous souhaitions faire est de corriger l'URL utilisée par l'action postComment. Tout comme précédemment, Play utilise ici le routage par défaut. Spécifions une nouvelle route propre à l'action de publication de commentaire :
POST /posts/{postId}/comments Application.postComment
Et voilà qui est fait ! Comme précédemment, n'oublions pas de commiter notre code dans Bazaar !