▼ |  | Web: PLT Web Applications

1 | Running Web Servlets
2 | Stateful Servlets
3 | Stateless Servlets
4 | HTTP: Hypertext Transfer Protocol
5 | URL-Based Dispatch
6 | Formlets: Functional Form Abstraction
7 | Templates: Separation of View
8 | Troubleshooting and Tips
| Index

► | 6 | Formlets: Functional Form Abstraction

6.1 | Basic Formlet Usage
6.2 | Syntactic Shorthand
6.3 | Functional Usage
6.4 | Predefined Formlets
6.5 | Utilities

On this page:

6.1`` Basic Formlet Usage
6.2`` Syntactic Shorthand
formlet
6.3`` Functional Usage
xexpr-forest/ c
formlet/ c
pure
cross
cross*
xml-forest
xml
text
tag-xexpr
formlet-display
formlet-process
6.4`` Predefined Formlets
make-input
text-input
password-input
checkbox
required
default
to-string
to-number
to-symbol
to-boolean
input-string
input-int
input-symbol
6.5`` Utilities
send/ formlet
embed-formlet

top ← prev up next →

### 6`` Formlets: Functional Form Abstraction

( require web-server/formlets )

The Web Server provides a kind of Web form abstraction called a formlet.

> > > Formlets originate in the work of the Links research group in their paper The Essence of Form Abstraction.

#### 6.1`` Basic Formlet Usage

Suppose we want to create an abstraction of entering a date in an HTML form. The following formlet captures this idea:

( define date-formlet
( formlet
(div
"Month:" ,{ input-int . => . month}
"Day:" ,{ input-int . => . day})
( list month day)))

The first part of the formlet syntax is the template of an X-expression that is the rendering of the formlet. It can contain elements like ,( => formlet name) where formlet is a formlet expression and name is an identifier bound in the second part of the formlet syntax.

This formlet is displayed (with formlet-display) as the following X-expression forest (list):

( list
'(div "Month:" (input ([name "input_0"]))
"Day:" (input ([name "input_1"]))))

date-formlet not only captures the rendering of the form, but also the request processing logic. If we send it an HTTP request with bindings for "input_0" to "10" and "input_1" to "3", with formlet-process, then it returns:

( list 10 3)

which is the second part of the formlet syntax, where month has been replaced with the integer represented by the "input_0" and day has been replaced with the integer represented by the "input_1".

The real power of formlet is that they can be embedded within one another. For instance, suppose we want to combine two date forms to capture a travel itinerary. The following formlet does the job:

( define travel-formlet
( formlet
(div
"Name:" ,{ input-string . => . name}
(div
"Arrive:" ,{date-formlet . => . arrive}
"Depart:" ,{date-formlet . => . depart})
( list name arrive depart))))

(Notice that date-formlet is embedded twice.) This is rendered as:

( list
'(div
"Name:"
(input ([name "input_0"]))
(div
"Arrive:"
(div "Month:" (input ([name "input_1"]))
"Day:" (input ([name "input_2"])))
"Depart:"
(div "Month:" (input ([name "input_3"]))
"Day:" (input ([name "input_4"]))))))

Observe that formlet-display has automatically generated unique names for each input element. When we pass bindings for these names to formlet-process, the following list is returned:

( list "Jay"
( list 10 3)
( list 10 6))

The rest of the manual gives the details of formlet usage and extension.

#### 6.2`` Syntactic Shorthand

( require web-server/formlets/syntax )

Most users will want to use the syntactic shorthand for creating formlets.

( formlet rendering yields-expr)

Constructs a formlet with the specified rendering and the processing resulting in the yields-expr expression. The rendering form is a quasiquoted X-expression, with two special caveats:
,{ => formlet-expr name} embeds the formlet given by formlet-expr; the result of this processing this formlet is available in the yields-expr as name.
(#%# xexpr ... ) renders an X-expression forest.

#### 6.3`` Functional Usage

( require web-server/formlets/lib )

The syntactic shorthand abbreviates the construction of formlets with the following library. These combinators may be used directly to construct low-level formlets, such as those for new INPUT element types. Refer to Predefined Formlets for example low-level formlets using these combinators.

xexpr-forest/c : contract?

Equivalent to ( listof xexpr/c )

( formlet/c content) → contract?
content : any/c

Equivalent to ( -> integer? ( values xexpr-forest/c ( -> ( listof binding? ) ( coerce-contract 'formlet/c content)) integer? )).
A formlet’s internal representation is a function from an initial input number to an X-expression forest rendering, a processing function, and the next allowable input number.

( pure value) → ( formlet/c any/c )
value : any/c

Constructs a formlet that has no rendering and always returns value in the processing stage.

( cross f g) → ( formlet/c any/c )
f : ( formlet/c ( any/c . -> . any/c ))
g : ( formlet/c any/c )

Constructs a formlet with a rendering equal to the concatenation of the renderings of formlets f and g; a processing stage that applies g’s processing result to f’s processing result.

( cross* f g ...) → ( formlet/c any/c )
f : ( formlet/c (() () #:rest ( listof any/c ) . ->* . any/c ))
g : ( formlet/c any/c )

Equivalent to cross lifted to many arguments.

( xml-forest r) → ( formlet/c procedure? )
r : xexpr-forest/c

Constructs a formlet with the rendering r and the identity procedure as the processing step.

( xml r) → ( formlet/c procedure? )
r : xexpr/c

Equivalent to ( xml-forest ( list r)).

( text r) → ( formlet/c procedure? )
r : string?

Equivalent to ( xml r).

( tag-xexpr tag attrs inner) → ( formlet/c any/c )
tag : symbol?
attrs : ( listof ( list/c symbol? string? ))
inner : ( formlet/c any/c )

Constructs a formlet with the rendering ( list ( list* tag attrs inner-rendering)) where inner-rendering is the rendering of inner and the processing stage identical to inner.

( formlet-display f) → xexpr-forest/c
f : ( formlet/c any/c )

Renders f.

( formlet-process f r) → any/c
f : ( formlet/c any/c )
r : request?

Runs the processing stage of f on the bindings in r.

#### 6.4`` Predefined Formlets

( require web-server/formlets/input )

These formlets are the main combinators for form input.

( make-input render) → ( formlet/c ( or/c false/c binding? ))
render : ( string? . -> . xexpr/c )

This formlet is rendered with render, which is passed the input name, and results in the extracted binding.

( text-input | [ | #:value value |
|  | #:size size |
|  | #:max-length max-length |
|  | #:read-only? read-only? |
|  | #:attributes attrs]) |

→ ( formlet/c ( or/c false/c binding? ))
value : ( or/c false/c bytes? ) = #f
size : ( or/c false/c exact-nonnegative-integer? ) = #f
max-length : ( or/c false/c exact-nonnegative-integer? ) = #f
read-only? : boolean? = #f
attrs : ( listof ( list/c symbol? string? )) = empty

This formlet renders using an INPUT element with the TEXT type and the attributes given in the arguments.

( password-input | [ | #:value value |
|  | #:size size |
|  | #:max-length max-length |
|  | #:read-only? read-only? |
|  | #:attributes attrs]) |

→ ( formlet/c ( or/c false/c binding? ))
value : ( or/c false/c bytes? ) = #f
size : ( or/c false/c exact-nonnegative-integer? ) = #f
max-length : ( or/c false/c exact-nonnegative-integer? ) = #f
read-only? : boolean? = #f
attrs : ( listof ( list/c symbol? string? )) = empty

This formlet renders using an INPUT element with the PASSWORD type and the attributes given in the arguments.

( checkbox value checked? [#:attributes attrs])
→ ( formlet/c ( or/c false/c binding? ))
value : bytes?
checked? : boolean?
attrs : ( listof ( list/c symbol? string? )) = empty

This formlet renders using a INPUT elemen with the CHECKBOX type and the attributes given in the arguments.

( required f) → ( formlet/c bytes? )
f : ( formlet/c ( or/c false/c binding? ))

Constructs a formlet that extracts the binding:form-value from the binding produced by f, or errors.

( default def f) → ( formlet/c bytes? )
def : bytes?
f : ( formlet/c ( or/c false/c binding? ))

Constructs a formlet that extracts the binding:form-value from the binding produced by f, or returns def.

( to-string f) → ( formlet/c string? )
f : ( formlet/c bytes? )

Converts f’s output to a string. Equivalent to ( cross ( pure bytes->string/utf-8 ) f).

( to-number f) → ( formlet/c number? )
f : ( formlet/c string? )

Converts f’s output to a number. Equivalent to ( cross ( pure string->number ) f).

( to-symbol f) → ( formlet/c symbol? )
f : ( formlet/c string? )

Converts f’s output to a symbol. Equivalent to ( cross ( pure string->symbol ) f).

( to-boolean f) → ( formlet/c boolean? )
f : ( formlet/c bytes? )

Converts f’s output to a boolean, if it is equal to #"on".

input-string : ( formlet/c string? )

Equivalent to ( to-string ( required ( text-input ))).

input-int : ( formlet/c integer? )

Equivalent to ( to-number input-string ).

input-symbol : ( formlet/c symbol? )

Equivalent to ( to-symbol input-string ).

#### 6.5`` Utilities

( require web-server/formlets/servlet )

A few utilities are provided for using formlets in Web applications.

( send/formlet f [#:wrap wrapper]) → any/c
f : ( formlet/c any/c )

| wrapper |  | : |  | ( xexpr/c . -> . response/c )

=

( lambda (form-xexpr)
`(html (head (title "Form Entry"))
(body ,form-xexpr)))

Uses send/suspend to send f’s rendering (wrapped in a FORM tag whose action is the continuation URL (wrapped again by wrapper)) to the client. When the form is submitted, the request is passed to the processing stage of f.

( embed-formlet embed/url f) → xexpr/c
embed/url : embed/url/c
f : ( formlet/c any/c )

Like send/formlet, but for use with send/suspend/dispatch.
top ← prev up next →