Construire le formulaire d’avis
Objectif : Créer un formulaire qui transmet le commentaire et l’identifiant de la randonnée à une action serveur.
Un avis doit être associé à la bonne randonnée et transmis sans exposer l’accès à la base de données dans le navigateur. Dans cette leçon, vous reliez le formulaire de la fiche détail à une action serveur et identifiez les valeurs qu’elle recevra.
1. Relier le formulaire à l’action serveur
La fiche de randonnée est déjà un composant serveur, comme vous l’avez vu dans « Repérer les composants serveur dans l’App Router ». Vous pouvez donc lui associer directement une action serveur au formulaire, sans ajouter de composant client pour cette soumission. Le formulaire HTML envoie les champs avec `FormData` lorsque la personne publie son avis.
Pour cette étape, l’action `ajouterAvis` est importée depuis le fichier prévu par le contrat. Elle reçoit l’objet de formulaire ; son traitement complet sera construit dans les leçons suivantes. Vous utilisez ici son nom et son emplacement afin que le formulaire soit déjà relié au bon point d’entrée serveur.
import { notFound } from 'next/navigation';
import { ajouterAvis } from '../../actions/avis';
import { obtenirRandonnee } from '../../lib/randonnees';
export default async function RandonneePage({ params }) {
const { id } = await params;
const randonnee = await obtenirRandonnee(id);
if (!randonnee) {
notFound();
}
return (
<article className="rando-fiche">
<h1 className="rando-titre">{randonnee.nom}</h1>
<p>{randonnee.description}</p>
<p>{randonnee.difficulte} · {randonnee.distance} km</p>
<section className="rando-avis" aria-labelledby="titre-avis">
<h2 id="titre-avis">Avis</h2>
{randonnee.avis.length === 0 ? (
<p className="rando-etat">Aucun avis pour le moment.</p>
) : (
randonnee.avis.map((avis) => <p key={avis.id}>{avis.texte}</p>)
)}
</section>
<form className="rando-formulaire" action={ajouterAvis}>
<input type="hidden" name="randonneeId" value={randonnee.id} />
<label htmlFor="texte-avis">Votre avis</label>
<textarea
className="rando-champ"
id="texte-avis"
name="texte"
required
/>
<button className="rando-bouton" type="submit">
Publier l’avis
</button>
</form>
</article>
);
}La propriété `action` relie le formulaire à `ajouterAvis`. Le champ caché `randonneeId` transmet l’identifiant de la randonnée affichée ; le champ `texte` contient le commentaire. À la soumission, l’action pourra lire ces deux valeurs avec `formData.get('randonneeId')` et `formData.get('texte')`. Le navigateur les envoie comme données du formulaire, mais l’écriture en base reste une responsabilité côté serveur.
2. Comprendre les champs transmis
Chaque contrôle destiné à l’action doit porter un attribut `name`. Sans lui, sa valeur n’apparaît pas sous le nom attendu dans `FormData`. Ici, `name="texte"` et `name="randonneeId"` établissent le contrat entre le formulaire et l’action ; les identifiants `id` et `htmlFor` servent, eux, à associer le libellé au contrôle correspondant.
L’attribut `required` demande au navigateur de refuser la soumission si la zone de texte est vide. C’est un premier retour d’interface, pas une garantie de validité : une requête peut être envoyée sans suivre les contrôles du navigateur. Vous ne devez donc pas confondre cette contrainte HTML avec la validation serveur qui sera ajoutée ensuite.
- Reliez le formulaire à l’action serveur avec la propriété `action`.
- Donnez un attribut `name` à chaque valeur que l’action doit lire dans `FormData`.
- Transmettez l’identifiant de la randonnée dans un champ caché, sans le considérer comme fiable.
- Gardez l’accès aux données et les vérifications dans le code serveur.
Dans la prochaine leçon, vous vérifierez côté serveur les valeurs transmises avant toute écriture.