Tutoriel de David Shaffer/Formulaires

From OFSET Wiki

Jump to: navigation, search

Traduction de : Forms


Contents

[edit] Facile : Les champs textes

Créons un formulaire pour que l'utilisateur rentre des "informations personnelles" :

WAComponent subclass: #PersonalInformationView
 instanceVariableNames: 'name address gender sendEmailUpdates birthdate'
 classVariableNames: 
 poolDictionaries: 
 category: 'SCSeasideTutorial'
name
 ^name
name: aString
 name := aString
address
 ^address
address: aString
 address := aString
gender
 ^gender
gender: aString
 gender := aString
sendEmailUpdates
 ^sendEmailUpdates
sendEmailUpdates: aValue
 sendEmailUpdates := aValue
birthdate
 ^birthdate
birthdate: aDate
 birthdate := aDate

Commençons par demander le nom (champ texte) et l'adresse (zone de texte) :

renderContentOn: html
 html form: 
   [html spanClass: 'label' with: 'Name:'.
    html spanClass: 'field'
       with: [html textInputWithValue: self name
                   callback: [:v | self name: v]].
    html spanClass: 'label' with: 'Address:'.
    html spanClass: 'field'
       with: [html textAreaWithValue: self address
                   callback: [:v | self address: v]].
    html spanClass: 'button'
       with: [html submitButtonWithAction: [self save] text: 'Save']]
save
 self inform: self name , '--' , self address
style
^'
*.label {
   clear: both;
   float: left;
   width: 100px;
}
*.field {
   float: left;
   width: 200px;
}
*.button {
   clear: both;
   width: 200px;
   margin-left: 100px;
   margin-top: 10px;
   float: left;
}'

Notez que le bouton pour soumettre le formulaire utilise le même méchanisme que les liens. Les champs textes ansi que les zones de textes utilisent aussi les callbacks (blocs de code à exécuter). Pour chaque composant du formulaire, vous pouvez utiliser a bloc à un argument qui recevra la valeur du champ de saisie. Quand un champ est soumis, Seaside active les callback de tous les champs avant celui du bouton de validation. Ceci est très important car vous pouvez alors compter sur le fait que chaque bloc d'action à fait son travail (souvent uniquement une validation et un enregistrement du texte tapé). Donc, la méthode de sauvegarde peut compter sur le fait que tous les champs ont bien été validés et enregistrés si l'utilisateur y a mis quelque chose.

Comme ceci est une nouvelle classe, nous devons informer Seaside qu'il peut l'utiliser en tant qu'application (comme nous l'avons fait pour HelloWorldComponent). Evaluez :

PersonalInformationView registerAsApplication: 'personal'

Maintenant, amenez votre navigateur à la page http://localhost:9090/seaside/personal et vous devriez voir le formulaire :

Image:PersonalInformationView1.png

Essayez d'entrer des valeurs et de soumettre le formulaire. Commencez une nouvelle session avec le composant et envoyer le formulaire (sans rien remplir). Notez que vous avez à l'écran l'affichage d'une trace de la pile d'appels qui indique une erreur et un lien pour débugguer. Si vous cliquez sur le lien "Debug", un debugger souvrira dans la fenêtre Squeak. Essayez le et trouver d'où vient l'erreur. Si vous voulez, vous pouvez corriger l'erreur maintenant ou attendre plus loin dans ce tutorial quand nous parlerons de validation.

[edit] Méthodes pour simplifier l'entrée de texte

Très souvent, les blocs d'appels ressembleront à ceux au-dessus: ils prennent simplement le texte entré et le sauve (par exemple self name: value dans le code précédent. En plus, la valeur initiale viendra souvent d'un accesseur (comme self name, au-dessus). Seaside prévoit certaines méthodes qui font ça automatiquement pour vous. Le code ci-dessous s'exécute exactement de la même façon qu'au-dessus :

renderContentOn: html
  html form: 
    [html spanClass: 'label' with: 'Name:'.
     html spanClass: 'field' with: [html textInputOn: #name of: self].
     html spanClass: 'label' with: 'Address:'.
     html spanClass: 'field' with: [html textAreaOn: #address of: self].
     html spanClass: 'button'
          with: [html submitButtonWithAction: [self save] text: 'Save']]

Les méthodes textInputOn:of: et textAreaOn:of: prennent le nom (symbole) de la propriété à afficher et l'objet qui stocke cette propriété (objet qui peut retourner ou modifier la propriété). Seaside génère les noms de méthodes à partir des noms de propriétés en utilisant les conventions de nommage de Smalltalk. Par exemple, une propriété appelée #name utilisera les méthodes name et name: pour la lecture et l'écriture (dans cet ordre).

[edit] Listes

Seaside apporte plusieurs méthodes pour construire des listes. Le code suivant peut être ajouté pour gérer le sexe de la personne :

 html spanClass: 'label' with: 'Gender:'.
 html spanClass: 'field'
       with: [html
                selectFromList: #(Male Female)
                selected: self gender
                callback: [:v | self gender: v]].

Notez que l'argument selected: nous permet de spécifier quel est l'élément sélectionné par défaut (quand la liste est affichée la première fois). Seaside propose encore un raccourci pour le cas où l'on fait simplement appel à une méthode pour stocker la valeur et à une autre pour l'afficher :

 html spanClass: 'label' with: 'Gender:'.
 html spanClass: 'field'
       with: [html selectInputOn: #gender
                   of: self
                   list: #(Male Female)]

Mettons à jour save pour afficher le sexe :

save
 self inform: name , '--' , address , '--' , gender

Essayez l'application maintenant. Vous devriez voir une liste déroulante ou une liste de choix en fonction de votre navigateur pour sélectionner le sexe. Il y a plusieurs méthodes de génération de listes que je vous encourage à explorer. Regarder dans WAHtmlRenderer les méthodes qui commencent par select ou optionWithLabel:.

[edit] Boutons Radios

Dans notre précédent exemple, la liste ne semble pas très appropriée pour afficher deux éléments. Essayons d'afficher plutôt des boutons radios. Remplacez le code de la liste par celui-ci :

html spanClass: 'field'
     with: [|group|
            group := html radioGroup.
            html radioButtonInGroup: group
                 selected: self gender = #Male
                 callback: [self gender: #Male].
            html text: 'Male'; break.
            html radioButtonInGroup: group
                 selected: self gender = #Female
                 callback: [self gender: #Female].
            html text: 'Female'].

On ne peut sélectionner qu'un bouton dans un groupe. Vous commencez par demander à Seaside de créer un nouveau groupe en utilisant radioGroup. Ce groupe est utilisé comme premier argument de la méthode de création d'un bouton radio. L'argument selected: permet de dire au navigateur s'il devra ou non sélectionner cet élément par défaut. Notez que, dans notre exemple, nous sélectionnons un bouton si celui-ci correspond à la valeur actuelle du sexe de la personne. Comme cela, le formulaire reflète la valeur actuelle du composant. L'argument callback: doit être un bloc à zéro argument qui sera exécuté si l'option correspondante a été sélectionnée par l'utilisateur. Notez que le bloc n'est pas appelé pour les options non sélectionnés.

[edit] Cases à cocher

Les cases à cocher sont très utiles pour des demandes booléennes (oui ou non). Regardons la variable d'instance sendEmailUpdates de notre composant. Nous souhaiterions afficher une case à cocher pour ce champ. Ajout ce code à l'intérieur du block form::

html spanClass: 'label' with: 'Updates:'.
html spanClass: 'field' 
          with: [html checkboxOn: #sendEmailUpdates
                              of: self].

Ceci est la version courte. Il y a bien sûr une méthode checkboxWithValue:callback:. Mettez à jour la méthode d'affichage pour vérifier la valeur de ce champ :

save
  self inform: name , '--' , address , '--' , gender , '--' , sendEmailUpdates printString

Essayer cette application maintenant. (Notez que la case à cocher est sélectionnée par défaut même si la valeur de la variable est nil). Remplissez le formulaire et validez le pour vérifier que la case à cocher fonctionne.

[edit] Champ date

La façon la plus simple de demander une date à l'utilisateur est d'utiliser dateInputWithValue:callback:. Ajouter ce code à l'intérieur du block form: :

html spanClass: 'label' with: 'Birthdate:'.
html spanClass: 'field'
          with: [html dateInputWithValue: self birthdate
                                callback: [:v | self birthdate: v]].

Et mettez à jour la fonction d'affichage :

save
  self inform: name , '--', address, '--', gender, '--', sendEmailUpdates printString,
                      '--', self birthdate printString

Si vous essayez de voir ce composant dans votre browser, vous allez récupérer une erreur car, contrairement aux autres composants, le champ date n'apprécie pas d'avoir nil comme valeur de départ. Nous devons lui passer une valeur raisonnable. Modifiez la méthode de lecture de la date de naissance pour initialiser la variable :

birthdate
  ^birthdate ifNil: [birthdate := Date today]

Maintenant, chargez l'application dans le navigateur et tout devrait bien marcher.

[edit] Rendu final

Affichez l'application. Elle devrait ressembler à celle-ci :

Image:PersonalInformationView2.png

Personal tools