Gathering inputs using form-controls

<-Previous | ^UP^ | Next->

html defines a number of input types which are used to gather inputs from users. In GendL, each input type is called a form control. Form Controls are implemented as objects. The following table shows the most commonly used html form types and the associated gendL object

html typeGendL object
<input type="text">text-form-control
<input type="number">number-form-control
<input type="password">password-form-control
<input type="checkbox">checkbox-form-control
<input type="radio">radio-form-control
<select>menu-form-control

Displaying a form control

Once a form control object has been created, there are a number of ways to display it in a web form

  • Use the form control objects :form-control message. This evaluates to the basic html string required for the form control
  • Define a :prompt input for the form control object and use the form control objects :prompt and :form-control messages and do your own custom layout
  • Define a :prompt input for the form control object and use the form control objects :html-string message to display a label and the form control html
  • Define a :layout-position input for the form control object to give more control over where the label is positioned in the html-string

(define-object form-control-layout (base-html-page):computed-slots((additional-header-content (with-lhtml-string()((:link :rel "stylesheet" :href "/style.css"))))(body (with-lhtml-string ()(when gwl:*developing?* (str (the development-links)))(:h3 "Just using the form-control message")(str (the fc-1 form-control))(:h3 "Using :prompt and form-control in my own table layout")(:table (:tr (:td (str (the fc-2 prompt)))(:td (str (the fc-2 form-control)))))(:h3 "Using html-string (defaulting to :layout-position :as-div)")(str (the fc-3 html-string))(:h3 "Using other :layout-position")(str (the fc-4 html-string))(:br)(str (the fc-5 html-string))))):objects((fc-1 :type 'text-form-control:size 12:default nil)(fc-2 :type 'text-form-control:size 12:prompt "My form control":default nil)(fc-3 :type 'text-form-control:size 12:prompt "My form control with html-string":default nil)(fc-4 :type 'text-form-control:size 12:prompt "Label display #1 - prepended label":default nil:label-position :prepend)(fc-5 :type 'text-form-control:size 12:prompt "Label display #2 - appended label":default nil:label-position :append)))

Form control inputs

Form controls can take a large number of inputs to provide the desired control. YADD provides a comprehensive guide to these inputs (GWL..base-form-control). We won't cover them all here, but the most common are

  • :default (required) - the default value for the form control
  • :prompt (optional) - the label associated with the form control
  • :layout-position (optional) - control over where the label is presented in the html-string message
  • :size (optional) - for text, number and password form controls it defines the length of the input box. For menu form controls it defines the number of options displayed
  • :choice-list (optional) - for menu and radio form controls, defines the options to be displayed. When selected the displayed value is the value returned by the form control
  • :choice-plist (optional) - for menu and radio form controls, defines the options to be displayed (value element of the plist). In contrast to choice-list, when an option is selected the form controls returns the plist keyword associated with the selected value

GWL-USER  (make-self 'menu-form-control:size 1:choice-list (list "Peter" "Paul" "John"):default "Peter")#<MENU-FORM-CONTROL #x2104C2296D>

GWL-USER (the form-control)

"<select name="TklM" id="TklM" size="1"> <option value="Peter" selected="selected">Peter</option> <option value="Paul">Paul</option> <option value="John">John</option></select>"

GWL-USER (the value)

"Peter"
GWL-USER  (make-self 'menu-form-control:size 1:choice-plist (list :name-1 "Peter" :name-2 "Paul" :name-3 "John"):default "Peter")#<MENU-FORM-CONTROL #x2104C2296D>

GWL-USER (the form-control)

"<select name="TklM" id="TklM" size="1"> <option value=":NAME-1" selected="selected">Peter</option> <option value=":NAME-2">Paul</option> <option value=":NAME-3">John</option></select>"

GWL-USER (the value)

:NAME-1

Returning values from Form Controls

Every form control support the :value message, which is the selected or entered value for the form control following form submission

Note that for text form controls, if the form control is empty on submission then NIL will be returned if the :nullify-empty-string? input to the form control is T, otherwise an empty string will be returned

Capturing a form control value

Any form containing form controls needs to be submitted in order for the form control entered value to be captured. The simplest, and reccomended, way to do this, is to use the :ajax-submit-on-change? input to the form control. With this set to T whenever the form control value is changed an AJAX update will be performed to submit the form and capture the value. We'll cover using AJAX in the next topic.

Resetting a form control

Every form constrol support a function restore-defaults! which sets :value, :failed-value and :error back to default values

Validating inputs

All form controls have a :validation-function input. This function defines the rule(s) against which the provided input is tested to determine if it is valid. Any function may be used, but quite often a lambda function is a good solution as the validation is generally specific to the form control and its applcation. The function return values are used to determine what happens with the input

  • If it returns nil, the input is considered invalid and the error slot is set to :unspecified-validation-fail
  • It may return a plist with keys :validated-value and :error. If :error is non-nil this signifies validation has failed and the error value will be appended to html-string
  • If any other value is returned, the input is considered valid

(define-object form-control-validation (base-html-page):computed-slots((main-sheet-body (with-lhtml-string ()(when gwl:*developing?* (str (the development-links)))(:h3 "Form control validation")(str (the fc-section main-div))))):objects((fc-section :type 'sheet-section:inner-html (with-lhtml-string ()(:p (str (the number-fc html-string)))(when (the number-fc value)(htm (:p (fmt "the number value is ~a"(the number-fc value)))))(when (the number-fc error)(html (:p (fmt "error is ~a, failed value is ~a"(the number-fc error)(the number-fc failed-value)))))))(number-fc :type 'number-form-control:default nil:size 12:ajax-submit-on-change? t:validation-function #'(lambda(input)(cond ((or (<= input 50) (>= input 60))(list :validated-value input:error :value-out-of-range))(T T))))))

Note that in the invalid entry, the text formatted red is output (and styled) as part of html-string, whilst the strings below it directly access the value, error and failed-value slots