
Widget
Overview
WARNING: the webapp framework is still an early prototype, so will be going through many changes during development
Widget
extends Weblet
to provide functionality to aid in creating reusable UI components.
Nesting
Widget has a fundamental difference from Weblet in that its entire output is buffered. The head
slot captures the output that will be written in the resulting <head>
tag. The body
slot captures the output that will be written to the <body>
tag.
Never call res.out
directly. Always use head
and body
. The buffers are used to support nesting of Widgets, so that every Widget has the opportunity to add content to the <head>
tag while the page is being written.
Widgets should assume the skeleton HTML markup will be written for them, and only output the <head>
and <body>
content that applies to it:
class MyWidget : Widget { override Void doGet() { head.title("My title!") body.h1("This is my widget!") } } // produces this markup... <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html xmlns='http://www.w3.org/1999/xhtml' xml:lang='en' lang='en'> <head> <meta http-equiv='Content-Type' content='text/html; charset=UTF-8'/> <title>My title!</title> </head> <body> <h1>This is my widget!</h1> </body> </html>
The complete
method is responsible for flushing the buffered output to the actual response OutStream. For GET requests this method is also responsible for outputing the supporting skeleton markup.
Actions
Widget also provides support for asynchronous actions. Actions are always invoked on a POST request. And are identified by a method qname, see doPost
for details.
Form submissions can use the action infrastructure as well. See actionForm
for details.
class MyWidget : Widget { override Void doGet() { head.title("My title!") actionForm(&foo) body.p body.textField("name='bar'") body.submit body.pEnd body.formEnd } Void foo() { echo("bar: " + req.form["bar"]) redirect(`/myWidget`) } }
Flash
TODO: this is what Rails calls this, but is there a better name?
The flash
field is a short-term storage that only exists for a single GET request, and is then automatically cleaned up. It is convenient for passing notifications following a POST.
class MyWidget : Widget { override Void doGet() { if (flash["foo"] != null) body.p.esc(flash["foo"]).pEnd actionForm(&foo) body.p body.textField("name='bar'") body.submit body.pEnd body.formEnd } Void foo() { flash["foo"] = "Did something with " + req.form["bar"]; redirect(`/myWidget`) } }