Tutoriel de David Shaffer/Formulaires
From OFSET Wiki
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 :
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 :



