ColdFusion Form Validation vs Python FormEncode

posted July 23rd 2005 at 0600 EDT in All, HTML, ColdFusion, Articles, Javascript, Python

I've been doing alot of work with validation in python recently, and wanted to point out a few nice things about validation in a python web app using FormEncode vs the client side validation in ColdFusion.

  1. Python validation with FormEncode is Server Side (not client side javascript)
  2. with FormEncode you see ALL the error messages at once. (not one at a time alert boxes)
  3. FormEncode messages are on the page, not in a dialog box which disapears
  4. FormEncode messages are both extendable, and combinable. (in CF you are kinda stuck with what you got, or mix client/server side validation & error messages)

First, lets review the standard (built in) way to do form validation in ColdFusion


<cfinput ..... name="mydate" required="yes"
    message="You must enter data in this field" validate="date">

 

Simple enough right? but the are a few things to be learned from other languages.

FormEncode has a nice separation from the display and the validation. I use zope page templates so I end up with the following HTML (it's really a zpt page)


<input .... name="mydate"> <form:error name=mydate" />
 

Or you could also use a custom error message


<form:iferror name="mydate">...</form:iferror>
 

FormEncode will replace the <form:error name="mydate" /> tag with a <span class="error-message">...</span> when there is an error. This allows you to specify in your html code where in the page the error should be displayed. It also allows you to style it as appropriate. When there is an error on that field, the input box also gets a class="error" appended to it (preserving the existing class names).

Thats the display. Specifying the validator happens is done by creating a "schema" for the form.


class Validator(Schema):
    mydate = validators.DateConvertor(not_empty=True)
 

There are of course a few other things which we would do to style some output. CSS is always nice.


input.error{border:1px solid #f00;border-color:#a00 #f66 #f66 #a00;color:#a00;}
span.error-message{padding:0 .5em 0 .5em;color:#fff;background-color: #f00;}
 

You can make up your mind, but I think that kind of error message is easier. I left out a few things though, because there is more magic that needs to happen to get the <form:error> tag to morph into the error message. FormEncode comes with htmlfill which processes the html page and fills it with the error message.

This is what a custom Fax number validate looks like, and how to use more than one validator.


class Validator(Schema)
    FaxNumber = FaxValidator()

class FaxValidator(validators.FancyValidator):

    messages={
        'invalidalpha':'Fax number must not contain alphabetic characters',
        'invalidchar':'Fax number cannot contain a %(part)s'
        }

    validNonNumeric = '() -+.'

    def validate_python(self,value,state):
        if not value:
            return None
        if len(value) == 0:
            return None

        numList = re.split("[,; :|]",value)
        for num in numList:
            if num == '' or num == ' ':
                continue
            digits = ''
            # pull the fax number out of its formatting and check length of number                                                     
            for part in num:
                if part.isdigit():
                    digits += part
                elif part.isalpha():
                    raise Invalid(self.message("invalidalpha",value),value,state)
                elif part not in self.validNonNumeric:
                    raise Invalid(self.message("invalidchar",value,part=part),value,state)
        return None
 

And the following schema declaration chains validators together on the same field.


class Validator(Schema):
    FaxNumber = All(FaxValidator(),validators.String(max=24,min=10))
 

Python validation is nice, and customizable. CF should lern a few things.

6 Responses

  1. #1 Raymond Camden
    3 years, 4 months ago

    Your first point, “Python validation with FormEncode is Server Side (not client side javascript)”, to me, reads like CF’s form validation is only client-side JS, which isn’t true. CF form validation can work client side, server side, or both. Just clarifying.

    I can see how some folks may prefer to separate the form field from the validation. CF supports that as well, and has for many versions, although most folks don’t use it. (And to be fair, it’s a bit icky.)

    You should also take a look at how form validation improved in CFMX7. It is rather easy, for example, to bind a regex to a form field for validation purposes. Much easier than writing an entire function for it.

  2. #2 Brandon Harper
    3 years, 4 months ago

    I think you might want to change your statements/arguments a little bit- for the most part this code is specific to the Zope framework/app server, not to Python itself.

    (I also do Python, though most of the time I write in CF).

  3. #3 jehiah
    3 years, 4 months ago

    @Raymond: Both good points. I need to check out the new forms features in CF7 (sadly I havn’t played with it much), and I realize you can obviously validate things on the server side (And should for good reasons). I’m not aware that the cfinput tag alone does that though I have in the past had to roll my own server side validation. As I have been doing some python recently I really liked doing the validation in one spot (server side) and how cleanly the messages showed on the client side.

    (And I think it’s easy to do the regex validation in CF6 as well with cfinput. I don’t think thats a new feature in CF7)

    @Brandon: yes you are right, my python examples are more towards Zope Page Templates and such, but hey, they are cool and easy =)

  4. #4 Murat
    3 years, 3 months ago

    You should examine the ASP.NET form validation. It generates validation JS automatically and it performs server-side validation without using any hidden form field or client-related value. Validation messages can be shown as inline HTML, summary HTML and JS alert box. The nice thing here a non-tech user cannot realize the location of the validation, because both of client-side and server-side validation generates the same output. Another nice thing that server-side validation is done automatically, no extra coding is required.

    However CF’s server-side validation requires tags and a logic to display validation messages.

  5. #5 ike
    3 years, 3 months ago

    I have to agree with Murat, even with ColdFusion 7, the server-side validation in CFFORM still relies on client-side input (hidden input elements), which means there is no genuinely server-side form validation native in ColdFusion. I’m certainly not going to move to .net for their form validation however. The onTap framework’s form validatin seems similar to what you described of Python (or Zope). I haven’t worked with either of them, however, the onTap framework has features for automating form validation from database metadata and for providing genuinely server-side validation (as well as client-side js) which by default are both displayed in an html summary (as you described, no annoying alert boxes, all errors displayed at once, stays visible). The one thing the framework doesn’t do (yet) that I see in this example is in-line error messages. But it’s all very extensible, and I may develop a feature for that if it’s popular.

  6. #6 roger
    3 years, 1 month ago

    Can anyone help me figure out how to inline-validate “select tags”..By the way, this example of mine is client-side validation…..

    function checkForm() {
    Projectnumber = document.getElementById(”Projectnumber”).value;
    Projectname = document.getElementById(”Projectname”).value;
    projectmanager = document.getElementById(”projectmanager”).value;

    if (Projectnumber == “BA-”) {
    hideAllErrors();
    document.getElementById(”ProjectnumberError”).style.display = “inline”;
    document.getElementById(”Projectnumber”).select();
    document.getElementById(”Projectnumber”).focus();
    return false;

    } else if (Projectname == “”) {
    hideAllErrors();
    document.getElementById(”ProjectnameError”).style.display = “inline”;
    document.getElementById(”Projectname”).select();
    document.getElementById(”Projectname”).focus();
    return false;

    } else if (projectmanager == “Not Selected”) {
    hideAllErrors();
    document.getElementById(”projectmanagerError”).style.display = “inline”;
    document.getElementById(”projectmanager”).select();
    document.getElementById(”projectmanager”).focus();
    return false;

    }
    return true;
    }

    function hideAllErrors() {
    document.getElementById(”ProjectnumberError”).style.display = “none”
    document.getElementById(”ProjectnameError”).style.display = “none”
    document.getElementById(”projectmanagerError”).style.display = “none”

    }

    Project Manager:

    Required: Please select your Project Manager

    Select a Project Manager

    #fullname#

Leave a comment