• Aucun résultat trouvé

5.5 Formulaire – premiers pas Le formulaire présenté à l'internaute sera le suivant :

Le modèle de la vue sera le modèle [ViewModel05] déjà utilisé précédemment. L'action qui affichera cette vue sera la suivante :

1. // Action06-GET

2. [HttpGet]

3. public ViewResult Action06() 4. {

5. return View("Action06Get",new ViewModel05()); 6. }

• ligne 2 : l'action ne peut être demandée que par une commande HTTP GET ;

• ligne 5 : la vue [/First/Action06Get.cshtml] sera affichée avec pour modèle une instance de type [ViewModel05]. La vue [/First/Action06Get.cshtml] sera la suivante :

1. @model Exemple_03.Models.ViewModel05

2. @using Exemple_03.Models 3. 4. @{ 5. Layout = null; 6. } 7. 8. <!DOCTYPE html> 9. 10.<html> 11.<head>

12. <meta name="viewport" content="width=device-width" /> 13. <title>Action06-GET</title>

14.</head> 15.<body>

16. <h3>Action06 - GET</h3>

17. <p>Choisissez une personne</p>

18. <form method="post" action="/First/Action06"> 19. <select name="personneId">

20. @foreach (Personne2 p in Model.Personnes) 21. { 22. string selected = ""; 23. if (p.Id == Model.SelectedId) 24. { 25. selected = "selected=\"selected\""; 26. }

27. <option value="@p.Id" @selected>@p.Prénom @p.Nom</option> 28. }

29. </select>

30. <input name="valider" type="submit" value="Valider" /> 31. </form>

32.</body> 33.</html>

Les principales nouveautés sont les suivantes :

• ligne 18 : pour que le navigateur puisse transmettre les informations saisies par un utilisateur, il nous faut un formulaire. C'est la balise <form> des lignes 18 et 31 qui le délimitent.

La balise HTML <form> a été présentée au paragraphe 2.5.2.1, page 34. Rappelons ses caractéristiques :

formulaire <form method="post" action="FormulairePost.aspx"> balise HTML <form name="..." method="..." action="...">...</form>

attributs name="frmexemple" : nom du formulaire

method="..." : méthode utilisée par le navigateur pour envoyer au serveur Web les valeurs récoltées dans le formulaire - facultatif

action="..." : URL à laquelle seront envoyées les valeurs récoltées dans le formulaire - facultatif

Un formulaire Web est entouré des balises <form>...</form>. Le formulaire peut avoir un nom (name="xx"). C'est le cas pour tous les contrôles qu'on peut trouver dans un formulaire. Ce nom est utile si le document Web contient des scripts qui doivent référencer des éléments du formulaire. Le but d'un formulaire est de rassembler des informations données par l'utilisateur au clavier/souris et d'envoyer celles-ci à une URL de serveur Web. Laquelle ? Celle référencée dans l'attribut action="URL". Si cet attribut est absent, les informations seront envoyées à l'URL du document qui a affiché le formulaire. Un client Web peut utiliser deux méthodes différentes appelées POST et GET pour envoyer des données à un serveur web. L'attribut method="méthode", avec method égal à GET ou POST, de la balise <form> indique au navigateur la méthode à utiliser pour envoyer les informations recueillies dans le formulaire à l'URL précisée par l'attribut action="URL". Lorsque l'attribut method n'est pas précisé, c'est la méthode GET qui est prise par défaut.

• ligne 18 : on voit que les valeurs du formulaire seront envoyées à l'URL [/First/Action06] par une commande HTTP POST ;

• ligne 30 : un formulaire doit avoir un bouton de type [submit]. C'est lui qui déclenche l'envoi des valeurs saisies à l'URL précisée par l'attribut [action] de la balise <form>.

Que va au juste transmettre le navigateur lorsque l'internaute va cliquer sur le bouton [Valider] ? Ceci a été expliqué au paragraphe 2.5.3.1, page 39. Rappelons ce qui avait été dit :

contrôle HTML visuel valeur(s) envoyée(s)

<input type="radio" value="Oui" name="R1"/>Oui

<input type="radio" name="R1" value="non" checked="checked"/>Non

R1=Oui

- la valeur de l'attribut value du bouton radio coché par l'utilisateur.

<input type="checkbox" name="C1" value="un"/>1

<input type="checkbox" name="C2" value="deux" checked="checked"/>2 <input type="checkbox" name="C3" value="trois"/>3

C1=un C2=deux

- valeurs des attributs value des cases cochées par l'utilisateur

<input type="text" name="txtSaisie"

size="20" value="qqs mots"/> txtSaisie=programmation+Web - texte tapé par l'utilisateur dans le champ de saisie. Les espaces ont été remplacés par le signe +

<input type="password" name="txtMdp"

size="20" value="unMotDePasse"/> txtMdp=ceciestsecret

- texte tapé par l'utilisateur dans le champ de saisie

<textarea rows="2" name="areaSaisie" cols="20"> ligne1 ligne2 ligne3 </textarea> areaSaisie=les+bases+de+la%0D%0A programmation+Web

- texte tapé par l'utilisateur dans le champ de saisie. %OD%OA est la marque de fin de ligne. Les espaces ont été remplacés par le signe +

<select size="1" name="cmbValeurs"> <option>choix1</option> <option selected="selected">choix2</option> <option>choix3</option> </select> cmbValeurs=choix3

- valeur choisie par l'utilisateur dans la liste à sélection unique

<select size="3" name="lst1"> <option selected="selected">liste1</option> <option>liste2</option> <option>liste3</option> <option>liste4</option> <option>liste5</option> </select> lst1=liste3

- valeur choisie par l'utilisateur dans la liste à sélection unique

<select size="3" name="lst2" multiple> <option selected="selected">liste1</option> <option>liste2</option> <option selected>liste3</option> <option>liste4</option> <option>liste5</option> </select> lst2=liste1 lst2=liste3

- valeurs choisies par l'utilisateur dans la liste à sélection multiple

<input type="submit" value="Envoyer"

name="cmdRenvoyer"/> cmdRenvoyer=Envoyer

- nom et attribut value du bouton qui a servi à envoyer les données du formulaire au serveur

<input type="hidden" name="secret"

value="uneValeur"/> secret=uneValeur

Dans notre formulaire, nous avons deux balises susceptibles d'envoyer une valeur :

1. <select name="personneId"> 2. ...

3. </select> et

1. <input name="valider" type="submit" value="Valider" /> Si l'internaute sélectionne la personne n° 2, les valeurs postées le seront sous la forme :

personneId=2&valider=Valider

Les noms des paramètres sont ceux des attributs [name] des balises concernées par le POST. Sans cet attribut, les balises n'émettent pas de valeur. Ainsi ci-dessus, on pourrait omettre l'attribut name="valider" du bouton [submit]. La valeur envoyée est l'attribut [value] du bouton. Ici cette information ne nous intéresse pas. Parfois les formulaires ont plusieurs boutons de type [submit]. Il est alors important de savoir quel bouton a été cliqué. On mettra alors l'attribut [name] aux différents boutons.

La balise <select> est composée d'une suite de balises <option> :

1. <select name="personneId">

2. <option value="1" >Pierre Martino</option>

3. <option value="2" selected=&quot;selected&quot;>Pauline Pereiro</option>

4. <option value="3" >Jacques Alfonso</option>

5. </select>

C'est la valeur de l'attribut [value] de l'option sélectionnée qui est postée. En d'absence de cet attribut, c'est le texte affiché par l'option, par exemple [Pierre Martino], qui est posté.

La chaîne

personneId=2&valider=Valider

va être postée à l'URL [/First/Action06] suivante :

1. // Action06-POST

2. [HttpPost]

3. public ViewResult Action06(ActionModel06 modèle) 4. {

5. return View("Action06Post",modèle); 6. }

On se rappelle peut-être que nous avions déjà une action [Action06] :

a) // Action06-GET

b) [HttpGet]

c) public ViewResult Action06() d) {

e) return View("Action06Get",new ViewModel05()); f) }

Il est possible d'avoir deux actions de même nom à condition qu'elle ne traite pas les mêmes commandes HTTP : • [Action06] de la ligne 3 gère un POST (ligne 2) ;

• [Action06] de la ligne c gère un GET (ligne b).

L'action [Action06] qui gère le POST va recevoir la chaîne de paramètres suivant :

personneId=2&valider=Valider

1. using System.ComponentModel.DataAnnotations;

2. namespace Exemple_03.Models

3. {

4. public class ActionModel06

5. {

6. [Required(ErrorMessage = "Le paramètre [personneId] est requis")] 7. public int PersonneId { get; set; }

8.

9. [Required(ErrorMessage = "Le paramètre [valider] est requis")] 10. public string Valider { get; set; }

11. } 12. }

L'action [Action06] reçoit ce modèle et le transmet tel quel à la vue [Action06Post] (ligne 5 de l'action) suivante :

1. @model Exemple_03.Models.ActionModel06

2. 3. @{ 4. Layout = null; 5. } 6. 7. <!DOCTYPE html> 8. 9. <html> 10.<head>

11. <meta name="viewport" content="width=device-width" /> 12. <title>Action06Post</title>

13.</head> 14.<body>

15. <h3>Action06 - POST</h3> 16. Valeurs postées :

17. <ul>

18. <li>ID de la personne sélectionnée : @Model.PersonneId</li> 19. <li>Commande utilisée : @Model.Valider</li>

20. </ul> 21.</body> 22.</html>

Le modèle est affiché aux lignes 18 et 19. Voyons un exemple :

En [1] on sélectionne la troisième personne d'[Id] égal à 3. En [2] on poste le formulaire. En [3], les valeurs reçues. En [4,5], on voit que la même URL a été appelée, l'une par un GET [4], l'autre par un POST [5]. Ceci ne se voit pas dans l'URL.

Dans la vue affichée à la suite du POST, on pourrait vouloir les nom et prénom de la personne sélectionnée plutôt que son numéro. Il faut alors faire évoluer la vue du POST et son modèle.

Nous créons une action [Action07] pour traiter ce cas. Cette action va devoir utiliser la session de l'utilisateur pour y stocker la liste des personnes. Nous allons suivre le modèle étudié au paragraphe 4.10, page 88 qui permet d'inclure les données de portée [Application] et [Session] dans le modèle de l'action.

Le modèle de la session sera la classe [SessionModel] suivante :

1. namespace Exemple_03.Models

2. {

3. public class SessionModel

4. {

5. public Personne2[] Personnes { get; set; } 6. }

7. }

• ligne 2 : la session mémorisera la liste des personnes affichées dans la liste déroulante ;

Il nous faut lier le type précédent [SessionModel] à un binder que nous appellerons [SessionModelBinder]. Celui-ci sera le même que celui décrit page 93 :

1. using System.Web.Mvc;

2.

3. namespace Exemple_03.Infrastructure

4. {

5. public class SessionModelBinder : IModelBinder 1

3 2

6. {

7. public object BindModel(ControllerContext controllerContext, ModelBindingContext

bindingContext) 8. {

9. // on rend les données de portée [Session]

10. return controllerContext.HttpContext.Session["data"]; 11. }

12. } 13. }

La liaison entre le modèle [SessionModel] et son binder [SessionModelBinder] se fait dans [Global.asax] :

1. public class MvcApplication : System.Web.HttpApplication

2. {

3. protected void Application_Start() 4. {

5. ... 6.

7. // model binders

8. ModelBinders.Binders.Add(typeof(SessionModel), new SessionModelBinder()); 9. }

10. // Session

11. public void Session_Start() 12. {

13. Session["data"] = new SessionModel(); 14. }

15. }

• ligne 8 : la liaison du modèle à son binder se fait dans [Application_Start] ;

• ligne 13 : une instance de type [SessionModel] est mise en session associée à la clé [data]. Ceci fait, l'action [Action07] est la suivante :

1. // Action07-GET

2. [HttpGet]

3. public ViewResult Action07(SessionModel session) 4. {

5. ViewModel05 modèleVue = new ViewModel05(); 6. session.Personnes= modèleVue.Personnes; 7. return View("Action07Get", modèleVue); 8. }

• ligne 3 : l'action récupère un type [SessionModel], donc la donnée de portée [Session] associée à la clé [data] ; • ligne 5 : on crée le modèle de la vue ;

• ligne 6 : on met dans la session le tableau des personnes. On en aura besoin dans la requête suivante, celle du POST. Le protocole HTTP est un protocole sans état. Il faut utiliser une session pour avoir de la mémoire entre les requêtes. Une session est propre à un utilisateur et est gérée par le serveur web ;

• ligne 7 : la vue [Action07Get.cshtml] est affichée. C'est la suivante :

1. @model Exemple_03.Models.ViewModel05

2. @using Exemple_03.Models

3. ... 4. <body>

5. <h3>Action07 - GET</h3>

6. <p>Choisissez une personne</p>

7. <form method="post" action="/First/Action07"> 8. ....

9. </form> 10.</body> 11.</html>

Elle est identique à la vue [Action06Get.cshtml] déjà étudiée. La principale différence est ligne 7 : l'URL à laquelle seront postées les valeurs du formulaire. Celles-ci seront traitées par l'action [Action07] suivante :

1. // Action07-POST

2. [HttpPost]

3. public ViewResult Action07(SessionModel session, ActionModel06 modèle) 4. {

5. Personne2 personne = session.Personnes.Where(p => p.Id == modèle.PersonneId).First<Personne2>();

6. string strPersonne = string.Format("{0} {1}", personne.Prénom, personne.Nom); 7. return View("Action07Post", (object)strPersonne);

8. }

• ligne 3 : les valeurs postées sont encapsulées dans le modèle d'action [ActionModel06] déjà utilisé précédemment :

using System.ComponentModel.DataAnnotations;

namespace Exemple_03.Models

{

public class ActionModel06

{

[Required(ErrorMessage = "Le paramètre [personneId] est requis")] public int PersonneId { get; set; }

[Required(ErrorMessage = "Le paramètre [valider] est requis")] public string Valider { get; set; }

} }

• ligne 3 : le premier paramètre est la donnée de portée [Session] associée à la clé [data] ; • ligne 5 : une requête LINQ récupère la personne ayant l'[Id] qui a été posté ;

• ligne 6 : on construit la chaîne de caractères qui doit être affichée par la vue [Action07Post] (ligne 8) ; • ligne 7 : pour appeler la bonne méthode [View], il faut transtyper le type [string] en [object].

La vue [Action07Post.cshtml] est la suivante :

1. @model string 2. 3. @{ 4. Layout = null; 5. } 6. 7. <!DOCTYPE html> 8. 9. <html> 10.<head>

11. <meta name="viewport" content="width=device-width" /> 12. <title>Action07-Post</title>

13.</head> 14.<body>

15. <h3>Action07-POST</h3>

16. Vous avez sélectionné [@Model]. 17.</body>

18.</html>

• ligne 1 : le modèle est de type [string] ; • ligne 16 : la chaîne de caractères est affichée. Voici un exemple d'exécution :