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

Reply via email to