DevLearningTools

MODULE 13 · LESSON 02

Form Validation

Validating form input: cfinput's client-side validation attributes, why server-side validation is still non-negotiable, and enforcing it for real with isValid() and cfparam.

New lessons are added one at a time as the course gets built out — a graded quiz for each lesson is still on the way.

The previous lesson covered how a form's fields arrive in the form scope, and introduced cfform's cfinput control. This lesson covers validating what actually arrives: cfinput's client-side checks, and, more importantly, isValid() and cfparam for validating it again on the server, since client-side validation only stops a well-behaved browser.

Learning Objectives

After completing this lesson, you'll be able to:

  • Use cfinput's validation attributes for client-side checks.
  • Validate a submitted value's real type or format server-side with isValid().
  • Use cfparam to enforce a field's type and presence.
  • Explain why server-side validation is required regardless of what the browser already checked.

Why Both Layers Exist

User Submits

cfinput / HTML5 Checks (Browser)

Reaches the Server Regardless

isValid() / cfparam Confirms It's Actually Safe

NOTE

A request sent directly to the action page, bypassing the browser entirely, skips client-side validation completely. The server-side check is the only one that can't be skipped.

Client-Side: cfinput's Validation Attributes

AttributeMeaning
requiredMarks the field mandatory (default false)
validateA built-in type: date, eurodate, time, float, integer, telephone, zipcode, creditcard, social_security_number, email, or regular_expression
patternA custom regular expression, used with validate="regular_expression"
rangeMinimum,maximum bounds for a numeric field
messageThe error text shown on validation failure (one message per field)
validateAtWhen the check runs: onSubmit (default), onBlur, or onServer
NOTE

Adobe's own documentation flags a real gotcha: the validation algorithm used for date/time values in onSubmit/onBlur checks is different from the one used server-side, the two can genuinely disagree on the same input.

A Real Example: Client-Side Validation on a Registration Form

Tag Syntax
<cfform action="process-registration.cfm" method="post">
    <cfinput type="text" name="phone" validate="telephone" message="Enter a valid phone number.">
    <cfinput type="text" name="email" required="yes" validate="email" message="Enter a valid email address.">
    <cfinput type="text" name="age" validate="range" range="18,120" message="Age must be between 18 and 120.">
    <cfinput type="submit" name="submitBtn" value="Register">
</cfform>

Server-Side: isValid()

isValid(type, value) checks whether a value actually matches a given type or format, returning a plain boolean rather than stopping execution, which makes it the right tool for building a real list of field-level errors.

typeChecks
emailA valid email address format
integer / float / numericThe value is a number of that kind
rangeA numeric value falls within a min/max, passed as the third and fourth arguments
regex / regular_expressionThe value matches a supplied pattern
telephone / zipcode / creditcard / ssnU.S.-specific formats: phone number, ZIP code, a 13–16 digit credit card number (mod10), or a social security number
urlA valid http, https, ftp, file, mailto, or news URL
guid / uuidA properly formatted GUID or UUID
variableNameA string that's a valid CFML variable name
Tag Syntax
<cfif structKeyExists(form, "submitted")>
    <cfif not isValid("email", form.email)>
        <cfset fieldErrors.email = "Please enter a valid email address.">
    </cfif>
    <cfif not isValid("range", form.age, 18, 120)>
        <cfset fieldErrors.age = "Age must be between 18 and 120.">
    </cfif>
</cfif>

Server-Side: cfparam for Enforced Type and Presence

Tag Syntax
<cfparam name="form.age" type="numeric">
NOTE

Unlike isValid(), cfparam doesn't return a boolean, it throws an exception immediately if form.age doesn't exist or isn't numeric. That makes it a good fit for a field the request genuinely can't proceed without, ideally paired with a cftry/cfcatch from Module 12 for a graceful message instead of the default error page.

A Real Example: Building a Structured fieldErrors Response

This combines this lesson with the throwing-exceptions lesson's structured extendedInfo pattern, checking each field with isValid(), collecting every failure into one struct instead of stopping at the first one.

CFScript
fieldErrors = {};

if (!structKeyExists(form, "newsletter")) {
    form.newsletter = "false"; // unchecked checkbox never submits
}

if (!isValid("email", form.email)) {
    fieldErrors.email = "Please enter a valid email address.";
}
if (!isValid("range", form.age, 18, 120)) {
    fieldErrors.age = "Age must be between 18 and 120.";
}

if (structCount(fieldErrors) > 0) {
    throw(type = "Validation", message = "Registration validation failed.", extendedInfo = serializeJSON(fieldErrors));
}

Common Beginner Mistakes

Relying on cfinput/HTML5 client-side validation alone

A request sent directly to the action page, bypassing the browser, skips it entirely. Server-side validation with isValid() or cfparam is the only check that actually can't be bypassed.

Assuming cfparam's type check gracefully returns false on failure

It throws an exception, it doesn't return a boolean the way isValid() does. Wrap it in cftry/cfcatch if a graceful message is needed instead of the default error page.

Assuming client-side and server-side date/time validation always agree

Adobe's own documentation notes the algorithms differ between onSubmit/onBlur validation and server-side validation, the same date/time input can pass one and fail the other.

Stopping at the first invalid field instead of collecting every error

Checking each field with isValid() and collecting every failure into a struct gives the user one useful response instead of forcing a resubmit-and-discover cycle for each field.

Best Practices

  • Validate server-side every time, regardless of what cfinput or HTML5 already checked in the browser.
  • Use isValid() for checks that should collect into a field-level error list rather than hard-stop the request.
  • Reserve cfparam for fields the request genuinely cannot proceed without, and pair it with cftry/cfcatch for a graceful failure message.
  • Default a possibly-missing checkbox/radio field (from the previous lesson's gotcha) before validating it.

Interview Questions

Why is server-side validation still required if cfinput already validates on the client?

A request sent directly to the action page, bypassing the browser entirely, skips client-side validation completely. Only a server-side check can't be bypassed.

What's the difference between isValid() and cfparam for validating a field?

isValid() returns a boolean, letting the code decide what to do and collect multiple errors. cfparam throws an exception immediately if the check fails, better suited to a field the request can't proceed without at all.

Name three type values isValid() accepts.

email, integer (or float/numeric), and range are common ones; regex, url, creditcard, zipcode, and telephone are also supported.

What real gotcha exists with date/time validation specifically?

Adobe's own documentation states the validation algorithm used for date/time values in client-side (onSubmit/onBlur) validation differs from the one used server-side, the same input can pass one and fail the other.

Summary

In this lesson, you used cfinput's validation attributes for client-side checks, validated real submitted values server-side with isValid() and cfparam, built a structured field-level error response, and covered why server-side validation is required no matter what the browser already checked.

What's Next?

The next lesson covers URL parameters: reading the url scope, and safely defaulting or validating a value that arrived in the query string instead of a submitted form.

MORE IN WEB DEVELOPMENT