On Dec 21, 2005, at 12:47 PM, Guyon Morée wrote:
After trying out differen form validation methods I settled on the
following:
@turbogears.expose(html="snippets.templates.register",
validators=validations.RegistrationValidation())
def register(self, **kw):
if kw: # user has entered form fields
if cherrypy.request.form_errors: # validate!
return {'input':kw,
'errors':cherrypy.request.form_errors}
else:
(save stuff)
return {'errors':{}, 'input':{}}
This way you can use the same url to show the form and to process it.
KID has now access to both the entered values and the error messages.
I liked this way of doing things and it got me to thinking about
doing a slight variation on it. Here's what I came up with for the
controller:
#
# math_controller.py
#
import turbogears
import cherrypy
from turbogears import controllers, validators
from formencode import Schema
class Area(Schema):
width = validators.Int()
height = validators.Int()
class MathController(controllers.Root):
@turbogears.expose(validators=Area(allow_extra_fields=True),
html="<project>.templates.math",
allow_json=True)
def area(self, **kw):
if cherrypy.request.form_errors:
errors = dict((key, str(value)) for key, value
in cherrypy.request.form_errors.items())
return dict(input=kw, errors=errors)
return dict(input=kw, errors={}, area=kw['width']*kw['height'])
Your root controller would need to do this to have access to it:
#
# controllers.py
#
class Root(controllers.Root):
math = MathController()
# (all your other controllers here)
The template looks something like this:
<input type="text" id="email_address" name="email_address"
value="${input.get('email_address', None)}"/> <span class="errormsg">
${errors.get('email_address', None)} </span>
And then I thought about getting the results via a little AJA(json),
so I wrote up the "math.kid" file like so (though, this could
definitely be improved by using the new widget objects):
#
# static/templates/math.kid
#
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:py="http://purl.org/
kid/ns#"
py:extends="'master.kid'">
<head>
<meta content="text/html; charset=UTF-8" http-equiv="content-
type" py:replace="''"/>
<title>Math Example</title>
<script src="${std.tg_js}/MochiKit.js">
</script>
<script type="text/javascript">
// <![CDATA[
function getArea(form) {
var data = {
'width': form.width.value,
'height': form.height.value,
'tg_format': 'json'
};
var dreq = loadJSONDoc('area?' + queryString(data));
dreq.addCallback(function(doc){
if (doc.area != undefined) {
replaceChildNodes($('area_value'), SPAN(null,
doc.area));
replaceChildNodes($('width_error'));
replaceChildNodes($('height_error'));
} else {
forEach(keys(doc.errors), function(key) {
var error_id = key + '_error';
var el = $(error_id);
if (el) {
replaceChildNodes(el, SPAN(null, doc.errors
[key]));
};
});
}
});
dreq.addErrback(function(error){
alert('problem getting area: '+error);
});
}
// ]]>
</script>
</head>
<body>
<form method="POST" action="area" onSubmit="getArea(this);return
false;">
<p>width: <input type="text" name="width" value="${input.get
('width')}" /><span id="width_error" /></p>
<p>height: <input type="text" name="height" value="$
{input.get('height')}" /><span id="height_error" /></p>
<p><input type="submit" value="calculate" /></p>
<p><b>area</b>: <span id="area_value">...</span></p>
</form>
</body>
</html>
The calculation is done behind the scenes and the value is put into
the 'area_value' element. And if there are errors, they are put in
their appropriate places, too.
This is a very simple example, and a lot more could be done with a
successful processing of the form data. And, well, area isn't a very
useful calculation... Has anyone thought of formalizing this kind of
pattern into some useful javascript library that comes standard with
TG, or of standardizing this kind of behind-the-scenes calculations
with the current widget framework?
--Tracy