Skip to content
Inaimathi edited this page Mar 6, 2011 · 2 revisions

Tutorial

An example form declaration using a general validation message:

(def-formlet login 
    (login-page ((user-name :text (lambda (f) (check-password user-name password))) 
    		 (password :password)) 
		:submit "Login"
		:general "You did not enter the correct user name or password")
  (start-session)
  (setf (session-value :user-name) user-name)
  (setf (session-value :user-id) (check-password user-name password))
  (redirect "/profile"))

If the validation function returns t, a session is started and the user is redirected to /profile. If it returns nil, the user will be sent to login-page, and a general error will be displayed just above the form. The fields in this formlet are user-name (a standard text input), and password (a password input). The submit button will read "Login" (by default, it reads "Submit").

You would display the above formlet as follows:

(define-easy-handler (login-page :uri "/") (form-values form-errors)
  (form-template (show-login-form form-values form-errors)))

The function show-login-formlet is declared as part of the def-formlet call above. Calling it with form-values and form-errors causes the full HTML of the formlet to be generated. If form-values contains any appropriate values, they will be displayed as default form values (this doesn't happen for passwords or recaptcha fields). If form-errors contains any appropriate values, they will be displayed alongside the associated input.

An example form using individual input validation:

(def-formlet register 
    (register-page 
     ((user-name :text (lambda (f) (and (not (equalp "" f)) (not (user-exists? f)))) "That name has already been taken")
      (password :password (longer-than? 4) "Your password must be longer than 4 characters")
      (confirm-password :password (lambda (f) (string= f password)) "You must enter the same password in 'confirm password'")
      (captcha :recaptcha))
     :submit "Register")
  (let ((id (register user-name password)))
    (start-session)
    (setf (session-value :user-name) user-name)
    (setf (session-value :user-id) id)
    (redirect "/profile")))

You'd display this the same way as above, and the same principles apply. The only difference is that, instead of a single error being displayed on a validation failure, one is displayed next to each input. In this case, it's a series of 4 (recaptchas are always validated the same way, so that was coded in the formlet module itself). If all of them pass, the user is redirected to /profile, otherwise a list of errors and user inputs is returned to register-page.

A single field looks like this (field-name :field-type validation-function "Error message")

  • The field name is used to generate a label, CSS id and name for the form field.
  • The type signifies what kind of input will be displayed (currently, the system supports only :text, :password, :textarea or :recaptcha. A special note, in order to use the :recaptcha input type, you need to setf the formlets:*private-key* and formlets:*public-key* as appropriate for your recaptcha account.
  • A validation function and error message can be provided optionally. If they aren't, the field won't be validated. If they are, then the function will be applied to the users' response. If the application fails, the error message will be pushed onto form-errors.

A formlet declaration breaks down as

(def-formlet [formlet name]
    ([source function]
     ([list of fields])
     :submit [submit button caption]
     :general [general error message]
     [on success])
  • Formlet name is used to generate the CSS id and name of the form, as well as determine the final name of this formlets' show-[name]-formlet function.
  • If the formlet fails validation, it will redirect the user to [source function] (the provided function must be expecting the form-values and form-errors arguments)
  • The list of fields should be one or more form fields as defined above
  • Submit button caption is just the text that will appear on this formlets' submit button. By default, it is "Submit"
  • If the [general error message] is present, it will be displayed above the form in the event of an error (and none of the individual warnings will be shown). This is useful for places like login forms, where you don't want to tell potential attackers which fields they got wrong.
  • Finally, [on success] is a body parameter that determines what to do if the form validates properly