Whatever message this page gives is out now! Go check it out!

cfloop: looping over a query

Last update:
May 18, 2026
Use the cfloop tag to loop over a query object, group a set of records, and modify the query object as you loop over the object.

Description

A loop over a query executes for each record in a query record set . The results are similar to those of the  cfoutput  tag. During each iteration, the columns of the current row are available for output. The  cfloop  tag loops over tags that cannot be used within a  cfoutput  tag.

Syntax

<cfloop  
    query = "query name"  
    startRow = "row number"  
    endRow = "row number"  
    group = "Query column" 
    groupCaseSensitive="true|false" 
>  
</cfloop>

History

ColdFusion (2018 update) Update 2: Added support for script variant of cfloop.

See also

For more information, see cfloop and cfbreak in Developing ColdFusion Applications.

Attributes

Attribute
Req/Opt
Default
Description
query
Required
Query that controls the loop. When using query attribute, you can now use dynamic references in addition to string, as shown in the following code:
<cfloop query="#getEmployees()#">
startRow
Optional
First row of query that is included in the loop.
endRow
Optional
Last row of query that is included in the loop.
group
groupcaseSensitive
Optional
Optional
Query column to use to group sets of records. Eliminates adjacent duplicate rows when data is sorted. Use if you retrieved a recordset ordered on one or more query columns. For example, if a recordset is ordered on "Customer_ID", you can group the output on "Customer_ID.".
Boolean value to determine whether table grouping needs to be case sentitive.

Example

 
<cfscript>
    myQuery = queryNew("id,name,amount","Integer,Varchar,Integer", 
                [ 
                        {id=1,name="One",amount=15}, 
                        {id=2,name="Two",amount=18}, 
                        {id=3,name="Three",amount=32} 
                ]); 
</cfscript>
<cfloop query = "myQuery"> 
    <cfoutput>#id#.#name#</cfoutput> <br/>
</cfloop>
Output
1.One

2.Two

3.Three
The cfloop tag also iterates over a record set with dynamic start and stop points. This gets the next n sets of records from a query. This example loops from the fifth through the tenth record returned by the MessageRecords query:
 
<cfscript>
    myQuery = queryNew("id,name,amount","Integer,Varchar,Integer", 
                [ 
                        {id=1,name="One",amount=15}, 
                        {id=2,name="Two",amount=18}, 
                        {id=3,name="Three",amount=32},
                        {id=4,name="Four",amount=37}, 
                        {id=5,name="Five",amount=79}, 
                        {id=6,name="Six",amount=26}
                ]); 
</cfscript>
<cfset Start = 3> 
<cfset End = 6> 
<cfloop query = "myQuery"
        startRow = "#Start#"
        endRow = "#End#"> 
    <cfoutput>#name# #amount#</cfoutput>
</cfloop>
Output
Three 32 Four 37 Five 79 Six 26
The loop stops when there are no more records, or when the current record index is greater than the value of the endRow attribute. The following example combines the pages that are returned by a query of a list of page names into one document, using the cfinclude tag:
<cfquery name = "GetTemplate" dataSource = "Library" maxRows = "5"> 
    SELECT TemplateName 
    FROM Templates 
</cfquery> 
<cfloop query = "GetTemplate"> 
    <cfinclude template = "#TemplateName#"> 
</cfloop>

Using groups in cfloop

You can use the group attribute in the following ways:
cfloop
<cfquery name = "result" datasource="cfcodeexplorer"> 
 SELECT ORDERID, CUSTOMERFIRSTNAME,STATE,CITY
 FROM ORDERS
 ORDER BY CITY
</cfquery> 

<cfloop query="result" group="CITY">
 <cfoutput>
  #result.CITY# <br/>
 </cfoutput>
</cfloop>
cfoutput
<cfquery name = "result" datasource="cfcodeexplorer"> 
 SELECT ORDERID, CUSTOMERFIRSTNAME,STATE,CITY
 FROM ORDERS
 ORDER BY CITY
</cfquery>

<cfoutput query="result" group="CITY">
 #result.CITY# <br/>
</cfoutput>
Output
Anytown

Boston

Cheyenne

Colorado Springs

Dallas

Deadwood

Denver

Greeley

Houston

Kansas City

Las Vegas

Los Angeles

New York

Oakland

Ogden

Phoenix

Santa Fe

Scottsdale

Seattle
You can also modify the query object as you loop over the object. For examples,
 
<!--- Create the query object --->
<cfset names = queryNew("")/>

<!--- Add the name column --->
<cfset queryAddColumn(
    names,
    "Name",
    "cf_sql_varchar",
    listToArray("John,James,Jason,Jared")
)/>

<!--- Add another column  --->

<cfset queryAddColumn(
    names,
    "Salary",
    "cf_sql_integer",
    arrayNew(1)
)/>

<!--- Populate the Salary column with random values --->

<cfloop query="names">
    <cfset names["Salary"][names.currentRow]=randRange(50000,90000)/>
</cfloop>

<!--- Dump the array result --->

<cfdump var="#names#"/>
Output
Using the attribute groups, you can also modify a query object, as shown below:
<cfset players = queryNew(
    "id, name, gender",
    "cf_sql_integer, cf_sql_varchar, cf_sql_varchar",
    [
        [ 1, "Ronaldo", "Male" ],
        [ 2, "Messi", "Male" ],
        [ 3, "Sharapova", "Female" ],
        [ 4, "Serena W", "Female" ],
        [ 5, "Hamilton", "Male" ]
    ]
) />

<cfquery dbtype="query" name="players">
    select * from players
    order by gender
</cfquery>

<cfoutput>
    <cfloop query="players" group="gender">
        <b>#players.gender#:</b><br/>
        <cfloop>
            #players.name# <br/>
        </cfloop>
        <br/>
    </cfloop>
</cfoutput>
Output
Female:
Sharapova
Serena W

Male:
Ronaldo
Messi
Hamilton

cfloop as script

 
<cfscript>
    myQuery = queryNew("id,name,amount","Integer,Varchar,Integer", [ {id=1,name="One",amount=15}, {id=2,name="Two",amount=18}, {id=3,name="Three",amount=32}, {id=4,name="Four",amount=37}, {id=5,name="Five",amount=79}, {id=6,name="Six",amount=26} ]);
    Start = 3;
    End = 6;
    cfloop(query = myQuery, startRow = "#Start#", endRow = "#End#") {
        writeOutput("#name# #amount#" & "<br/>");
    }
</cfscript>
Output
Three 32

Four 37

Five 79

Six 26

Real-world uses of the cflopp tag

List loop- Bulk email notifications

Your application needs to send notifications to multiple users when important events occur (e.g., system maintenance, new features, account updates). User email addresses are stored as comma-separated lists in configuration files or database fields. You need to process these lists and send individual emails to each recipient with proper error handling.
Problem statement
  • Email addresses stored as comma-delimited strings
  • Need to send email to each address individually
  • Must validate email format before sending
  • Track successful and failed sends
  • Handle large recipient lists efficiently
Solution
Use cfloop with "list" attribute to iterate over comma-separated values.
<cfscript>
    // Email configuration
    recipientList = "john.smith@example.com, jane.doe@example.com, bob.wilson@example.com, alice.johnson@example.com, invalid-email, charlie.brown@example.com";
    
    notificationSubject = "System Maintenance Notification";
    notificationMessage = "Our system will undergo scheduled maintenance on November 10, 2024, from 2:00 AM to 4:00 AM EST. During this time, services may be temporarily unavailable.";
    
    // Tracking variables
    successCount = 0;
    failCount = 0;
    successEmails = [];
    failedEmails = [];
    
    // Function to validate email
    function isValidEmail(email) {
        // Simple email validation regex
        emailPattern = "^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$";
        return reFind(emailPattern, trim(email)) GT 0;
    }
    
    // Function to simulate email sending (in production, use cfmail)
    function sendEmail(toEmail, subject, message) {
        try {
            // In production, this would be cfmail
            // For demo, we'll simulate success/failure
            if (isValidEmail(toEmail)) {
                // Simulate cfmail
                // <cfmail to="#toEmail#" from="noreply@example.com" subject="#subject#">#message#</cfmail>
                return {success: true, message: "Email sent successfully"};
            } else {
                return {success: false, message: "Invalid email format"};
            }
        } catch (any e) {
            return {success: false, message: e.message};
        }
    }
</cfscript>

<h2>Bulk Email Notification System</h2>

<!--- Display notification details --->
<div style="background: ##e3f2fd; border: 2px solid ##2196f3; padding: 20px; margin: 20px 0; border-radius: 5px;">
    <h3 style="margin-top: 0;">📧 Notification Details</h3>
    <p><strong>Subject:</strong> <cfoutput>#notificationSubject#</cfoutput></p>
    <p><strong>Message:</strong> <cfoutput>#notificationMessage#</cfoutput></p>
    <p><strong>Total Recipients:</strong> <cfoutput>#listLen(recipientList)#</cfoutput></p>
</div>

<!--- Process Form Submission --->
<cfif isDefined("form.action") AND form.action EQ "send">
    
    <h3>📨 Sending Notifications...</h3>
    
    <div style="background: white; border: 1px solid ##ddd; padding: 15px; margin: 20px 0; border-radius: 5px;">
        
        <!--- Loop through recipient list --->
        <cfloop list="#recipientList#" index="emailAddress">
            
            <cfscript>
                // Clean the email address (remove extra spaces)
                cleanEmail = trim(emailAddress);
                
                // Send email
                result = sendEmail(cleanEmail, notificationSubject, notificationMessage);
                
                // Track results
                if (result.success) {
                    successCount++;
                    arrayAppend(successEmails, cleanEmail);
                } else {
                    failCount++;
                    arrayAppend(failedEmails, {email: cleanEmail, error: result.message});
                }
            </cfscript>
            
            <!--- Display progress for each email --->
            <cfoutput>
                <div style="padding: 10px; margin: 5px 0; border-left: 4px solid #result.success ? '##4caf50' : '##f44336'#; background: #result.success ? '##e8f5e9' : '##ffebee'#;">
                    <strong>#result.success ? '✓' : '✗'#</strong> 
                    #cleanEmail# 
                    <span style="color: ##666; font-size: 12px;">- #result.message#</span>
                </div>
            </cfoutput>
            
        </cfloop>
        
    </div>
    
    <!--- Display Summary Statistics --->
    <div style="background: ##f5f5f5; border: 2px solid ##4caf50; padding: 20px; margin: 20px 0; border-radius: 5px;">
        <h3 style="margin-top: 0;">📊 Delivery Summary</h3>
        
        <div style="display: flex; justify-content: space-around; margin: 20px 0;">
            <div style="text-align: center;">
                <div style="font-size: 48px; color: ##4caf50; font-weight: bold;">
                    <cfoutput>#successCount#</cfoutput>
                </div>
                <div style="color: ##666;">Successful</div>
            </div>
            <div style="text-align: center;">
                <div style="font-size: 48px; color: ##f44336; font-weight: bold;">
                    <cfoutput>#failCount#</cfoutput>
                </div>
                <div style="color: ##666;">Failed</div>
            </div>
            <div style="text-align: center;">
                <div style="font-size: 48px; color: ##2196f3; font-weight: bold;">
                    <cfoutput>#listLen(recipientList)#</cfoutput>
                </div>
                <div style="color: ##666;">Total</div>
            </div>
        </div>
        
        <!--- Success Rate --->
        <cfset successRate = successCount / listLen(recipientList) * 100>
        <div style="text-align: center; margin-top: 20px;">
            <strong>Success Rate:</strong> 
            <span style="font-size: 24px; color: ##4caf50;">
                <cfoutput>#numberFormat(successRate, "0.0")#%</cfoutput>
            </span>
        </div>
    </div>
    
    <!--- Successful Emails --->
    <cfif arrayLen(successEmails) GT 0>
        <div style="background: ##e8f5e9; border: 2px solid ##4caf50; padding: 15px; margin: 15px 0; border-radius: 5px;">
            <h4 style="margin-top: 0; color: ##4caf50;">✓ Successfully Sent To:</h4>
            <ul>
                <cfloop array="#successEmails#" index="email">
                    <li><cfoutput>#email#</cfoutput></li>
                </cfloop>
            </ul>
        </div>
    </cfif>
    
    <!--- Failed Emails --->
    <cfif arrayLen(failedEmails) GT 0>
        <div style="background: ##ffebee; border: 2px solid ##f44336; padding: 15px; margin: 15px 0; border-radius: 5px;">
            <h4 style="margin-top: 0; color: ##f44336;">✗ Failed Recipients:</h4>
            <ul>
                <cfloop array="#failedEmails#" index="failedItem">
                    <cfoutput>
                        <li>
                            <strong>#failedItem.email#</strong> - 
                            <em style="color: ##666;">#failedItem.error#</em>
                        </li>
                    </cfoutput>
                </cfloop>
            </ul>
        </div>
    </cfif>
    
    <p>
        <a href="?" style="padding: 10px 20px; background: ##2196f3; color: white; text-decoration: none; border-radius: 5px; display: inline-block;">
            ← Back
        </a>
    </p>
    
<cfelse>
    
    <!--- Display recipient list --->
    <h3>👥 Recipient List</h3>
    
    <div style="background: white; border: 1px solid ##ddd; padding: 15px; margin: 20px 0; border-radius: 5px;">
        <table style="width: 100%; border-collapse: collapse;">
            <thead>
                <tr style="background: ##e0e0e0;">
                    <th style="padding: 10px; border: 1px solid ##ccc; text-align: left;">##</th>
                    <th style="padding: 10px; border: 1px solid ##ccc; text-align: left;">Email Address</th>
                    <th style="padding: 10px; border: 1px solid ##ccc; text-align: center;">Valid</th>
                </tr>
            </thead>
            <tbody>
                <!--- Loop through list with index --->
                <cfset counter = 0>
                <cfloop list="#recipientList#" index="emailAddress">
                    <cfset counter++>
                    <cfset cleanEmail = trim(emailAddress)>
                    <cfset isValid = isValidEmail(cleanEmail)>
                    
                    <tr>
                        <td style="padding: 10px; border: 1px solid ##ccc;"><cfoutput>#counter#</cfoutput></td>
                        <td style="padding: 10px; border: 1px solid ##ccc;"><cfoutput>#cleanEmail#</cfoutput></td>
                        <td style="padding: 10px; border: 1px solid ##ccc; text-align: center;">
                            <cfoutput>
                                <span style="padding: 5px 10px; background: #isValid ? '##4caf50' : '##f44336'#; color: white; border-radius: 3px;">
                                    #isValid ? '✓ Valid' : '✗ Invalid'#
                                </span>
                            </cfoutput>
                        </td>
                    </tr>
                </cfloop>
            </tbody>
        </table>
    </div>
    
    <!--- Send button --->
    <form method="post">
        <input type="hidden" name="action" value="send">
        <button type="submit" style="padding: 15px 30px; background: ##4caf50; color: white; border: none; border-radius: 5px; cursor: pointer; font-size: 16px; font-weight: bold;">
            📨 Send Notifications to All Recipients
        </button>
    </form>
    
</cfif>

<!--- List Processing Information --->
<h3>List Processing Details</h3>
<div style="background: ##f5f5f5; border: 1px solid ##ccc; padding: 15px; border-radius: 5px;">
    <cfoutput>
        <p><strong>List Variable:</strong> recipientList</p>
        <p><strong>Delimiter:</strong> Comma (,)</p>
        <p><strong>List Length:</strong> #listLen(recipientList)# items</p>
        <p><strong>Loop Type:</strong> cfloop list="##recipientList##" index="emailAddress"</p>
        <p><strong>Original List:</strong> <code style="background: white; padding: 5px; display: block; margin-top: 5px;">#recipientList#</code></p>
    </cfoutput>
</div>

Query loop- Customer order processing

Your e-commerce platform needs to display customer order history with detailed information about each order. Orders are retrieved from a database, and you need to present them in a user-friendly format with order details, status, and action buttons. The system must handle varying numbers of orders efficiently.
Problem statement
  • Need to display all orders from a database query
  • Each order requires custom formatting and calculations
  • Must show order status with color coding
  • Action buttons needed for each order (view, download, track)
  • Handle empty result sets gracefully
  • Calculate order subtotals and grand totals
Solution
Use cfloop with "query" attribute to iterate over database results.
<cfscript>
    // Simulate database query (in production, use cfquery with real database)
    ordersQuery = queryNew(
        "OrderID,CustomerName,OrderDate,Status,TotalAmount,ShippingAddress",
        "integer,varchar,date,varchar,decimal,varchar",
        [
            {
                OrderID: 10001,
                CustomerName: "John Smith",
                OrderDate: createDate(2024, 11, 1),
                Status: "Delivered",
                TotalAmount: 249.99,
                ShippingAddress: "123 Main St, Boston, MA"
            },
            {
                OrderID: 10002,
                CustomerName: "John Smith",
                OrderDate: createDate(2024, 11, 3),
                Status: "Shipped",
                TotalAmount: 89.50,
                ShippingAddress: "123 Main St, Boston, MA"
            },
            {
                OrderID: 10003,
                CustomerName: "John Smith",
                OrderDate: createDate(2024, 11, 5),
                Status: "Processing",
                TotalAmount: 449.00,
                ShippingAddress: "456 Oak Ave, Boston, MA"
            },
            {
                OrderID: 10004,
                CustomerName: "John Smith",
                OrderDate: createDate(2024, 11, 6),
                Status: "Pending",
                TotalAmount: 125.75,
                ShippingAddress: "123 Main St, Boston, MA"
            },
            {
                OrderID: 10005,
                CustomerName: "John Smith",
                OrderDate: createDate(2024, 11, 4),
                Status: "Cancelled",
                TotalAmount: 199.99,
                ShippingAddress: "123 Main St, Boston, MA"
            }
        ]
    );
    
    // Function to get status color
    function getStatusColor(status) {
        switch(status) {
            case "Delivered":
                return "##4caf50"; // Green
            case "Shipped":
                return "##2196f3"; // Blue
            case "Processing":
                return "##ff9800"; // Orange
            case "Pending":
                return "##9e9e9e"; // Grey
            case "Cancelled":
                return "##f44336"; // Red
            default:
                return "##000000"; // Black
        }
    }
</cfscript>

<h2>Customer Order History</h2>

<div style="background: ##e3f2fd; border: 2px solid ##2196f3; padding: 15px; margin: 20px 0; border-radius: 5px;">
    <strong>Customer:</strong> John Smith | 
    <strong>Total Orders:</strong> #ordersQuery.recordCount# | 
    <strong>Account Status:</strong> Active
</div>

<!--- Check if there are any orders --->
<cfif ordersQuery.recordCount GT 0>
    
    <!--- Initialize grand total --->
    <cfset grandTotal = 0>
    
    <!--- Loop through orders using cfloop query --->
    <cfloop query="ordersQuery">
        
        <!--- Calculate grand total --->
        <cfset grandTotal += ordersQuery.TotalAmount>
        
        <!--- Display each order --->
        <div style="border: 2px solid ##ddd; padding: 20px; margin: 15px 0; border-radius: 5px; background: white;">
            
            <!--- Order Header --->
            <div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 15px; border-bottom: 2px solid ##f0f0f0; padding-bottom: 10px;">
                <div>
                    <h3 style="margin: 0; color: ##333;">Order ##<cfoutput>#ordersQuery.OrderID#</cfoutput></h3>
                    <p style="margin: 5px 0; color: ##666;">
                        <strong>Placed:</strong> <cfoutput>#dateFormat(ordersQuery.OrderDate, "mmmm d, yyyy")#</cfoutput>
                    </p>
                </div>
                <div>
                    <cfoutput>
                        <span style="padding: 8px 15px; background: #getStatusColor(ordersQuery.Status)#; color: white; border-radius: 20px; font-weight: bold;">
                            #ordersQuery.Status#
                        </span>
                    </cfoutput>
                </div>
            </div>
            
            <!--- Order Details --->
            <div style="margin: 15px 0;">
                <cfoutput>
                    <p style="margin: 5px 0;">
                        <strong>Shipping Address:</strong> #ordersQuery.ShippingAddress#
                    </p>
                    <p style="margin: 5px 0;">
                        <strong>Order Total:</strong> <span style="font-size: 20px; color: ##2196f3; font-weight: bold;">#dollarFormat(ordersQuery.TotalAmount)#</span>
                    </p>
                </cfoutput>
            </div>
            
            <!--- Action Buttons --->
            <div style="margin-top: 15px; padding-top: 15px; border-top: 1px solid ##f0f0f0;">
                <cfoutput>
                    <a href="?action=view&orderID=#ordersQuery.OrderID#" style="padding: 8px 15px; background: ##2196f3; color: white; text-decoration: none; border-radius: 3px; margin-right: 10px;">
                        📋 View Details
                    </a>
                    
                    <cfif ordersQuery.Status EQ "Delivered" OR ordersQuery.Status EQ "Shipped">
                        <a href="?action=track&orderID=#ordersQuery.OrderID#" style="padding: 8px 15px; background: ##4caf50; color: white; text-decoration: none; border-radius: 3px; margin-right: 10px;">
                            📦 Track Package
                        </a>
                    </cfif>
                    
                    <cfif ordersQuery.Status EQ "Delivered">
                        <a href="?action=download&orderID=#ordersQuery.OrderID#" style="padding: 8px 15px; background: ##ff9800; color: white; text-decoration: none; border-radius: 3px;">
                            📥 Download Invoice
                        </a>
                    </cfif>
                    
                    <cfif ordersQuery.Status EQ "Pending">
                        <a href="?action=cancel&orderID=#ordersQuery.OrderID#" style="padding: 8px 15px; background: ##f44336; color: white; text-decoration: none; border-radius: 3px;" onclick="return confirm('Cancel this order?');">
                            ✖ Cancel Order
                        </a>
                    </cfif>
                </cfoutput>
            </div>
            
            <!--- Row number indicator --->
            <cfoutput>
                <div style="text-align: right; margin-top: 10px; color: ##999; font-size: 12px;">
                    Order #ordersQuery.currentRow# of #ordersQuery.recordCount#
                </div>
            </cfoutput>
            
        </div>
        
    </cfloop>
    
    <!--- Display Grand Total --->
    <div style="background: ##f5f5f5; border: 2px solid ##4caf50; padding: 20px; margin: 20px 0; border-radius: 5px; text-align: right;">
        <h3 style="margin: 0;">
            <strong>Total Spent:</strong> 
            <span style="color: ##4caf50; font-size: 24px;">
                <cfoutput>#dollarFormat(grandTotal)#</cfoutput>
            </span>
        </h3>
    </div>
    
<cfelse>
    
    <!--- No orders found --->
    <div style="background: ##fff3e0; border: 2px solid ##ff9800; padding: 30px; margin: 20px 0; border-radius: 5px; text-align: center;">
        <h3 style="color: ##ff9800;">📦 No Orders Found</h3>
        <p>You haven't placed any orders yet.</p>
        <a href="?action=shop" style="padding: 10px 20px; background: ##2196f3; color: white; text-decoration: none; border-radius: 5px; display: inline-block; margin-top: 10px;">
            Start Shopping
        </a>
    </div>
    
</cfif>

<!--- Query Details for Reference --->
<h3>Query Processing Details</h3>
<div style="background: ##f5f5f5; border: 1px solid ##ccc; padding: 15px; border-radius: 5px;">
    <cfoutput>
        <p><strong>Query Name:</strong> ordersQuery</p>
        <p><strong>Record Count:</strong> #ordersQuery.recordCount#</p>
        <p><strong>Column List:</strong> #ordersQuery.columnList#</p>
        <p><strong>Loop Type:</strong> cfloop query="ordersQuery"</p>
    </cfoutput>
</div>

Struct loop- Form data validation

Your web application has a complex registration form with multiple fields. You need to validate all submitted form fields dynamically, check for required fields, apply validation rules, and provide clear feedback about validation errors. The validation logic should be flexible and easy to maintain without hardcoding field names.
Problem statement
  • Forms have many fields that need validation
  • Need to iterate over all submitted form data
  • Different validation rules for different fields
  • Must check for required fields
  • Validate data types (email, phone, number, etc.)
Solution
Use cfloop with "collection" attribute to iterate over struct/form data.
<cfscript>
    // Define validation rules
    validationRules = {
        firstName: {required: true, type: "string", minLength: 2, label: "First Name"},
        lastName: {required: true, type: "string", minLength: 2, label: "Last Name"},
        email: {required: true, type: "email", label: "Email Address"},
        phone: {required: false, type: "phone", label: "Phone Number"},
        age: {required: true, type: "number", min: 18, max: 120, label: "Age"},
        country: {required: true, type: "string", label: "Country"},
        terms: {required: true, type: "boolean", label: "Terms & Conditions"}
    };
    
    // Initialize validation results
    validationErrors = {};
    isFormValid = true;
    
    // Function to validate email
    function validateEmail(email) {
        emailPattern = "^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$";
        return reFind(emailPattern, trim(email)) GT 0;
    }
    
    // Function to validate phone
    function validatePhone(phone) {
        // Simple phone validation (10 digits)
        phonePattern = "^\d{10}$";
        cleanPhone = reReplace(phone, "[^0-9]", "", "ALL");
        return len(cleanPhone) EQ 10;
    }
    
    // Function to validate single field
    function validateField(fieldName, fieldValue, rules) {
        errors = [];
        
        // Check if required
        if (rules.required AND (NOT isDefined("fieldValue") OR len(trim(fieldValue)) EQ 0)) {
            arrayAppend(errors, "#rules.label# is required");
            return errors;
        }
        
        // If field is optional and empty, skip validation
        if (NOT rules.required AND len(trim(fieldValue)) EQ 0) {
            return errors;
        }
        
        // Type-specific validation
        switch(rules.type) {
            case "email":
                if (NOT validateEmail(fieldValue)) {
                    arrayAppend(errors, "#rules.label# must be a valid email address");
                }
                break;
            case "phone":
                if (NOT validatePhone(fieldValue)) {
                    arrayAppend(errors, "#rules.label# must be a valid 10-digit phone number");
                }
                break;
            case "number":
                if (NOT isNumeric(fieldValue)) {
                    arrayAppend(errors, "#rules.label# must be a number");
                } else {
                    if (structKeyExists(rules, "min") AND fieldValue LT rules.min) {
                        arrayAppend(errors, "#rules.label# must be at least #rules.min#");
                    }
                    if (structKeyExists(rules, "max") AND fieldValue GT rules.max) {
                        arrayAppend(errors, "#rules.label# cannot exceed #rules.max#");
                    }
                }
                break;
            case "boolean":
                if (NOT isDefined("fieldValue") OR fieldValue NEQ "true") {
                    arrayAppend(errors, "You must accept #rules.label#");
                }
                break;
            case "string":
                if (structKeyExists(rules, "minLength") AND len(fieldValue) LT rules.minLength) {
                    arrayAppend(errors, "#rules.label# must be at least #rules.minLength# characters");
                }
                break;
        }
        
        return errors;
    }
</cfscript>

<h2>User Registration Form with Dynamic Validation</h2>

<!--- Process Form Submission --->
<cfif isDefined("form.submitted")>
    
    <h3>🔍 Validating Form Data...</h3>
    
    <!--- Loop through validation rules and validate each field --->
    <cfloop collection="#validationRules#" item="fieldName">
        
        <cfscript>
            // Get the field value from form
            fieldValue = isDefined("form.#fieldName#") ? form[fieldName] : "";
            
            // Get validation rules for this field
            rules = validationRules[fieldName];
            
            // Validate the field
            errors = validateField(fieldName, fieldValue, rules);
            
            // Store errors if any
            if (arrayLen(errors) GT 0) {
                validationErrors[fieldName] = errors;
                isFormValid = false;
            }
        </cfscript>
        
    </cfloop>
    
    <!--- Display Validation Results --->
    <cfif isFormValid>
        
        <div style="background: ##e8f5e9; border: 2px solid ##4caf50; padding: 20px; margin: 20px 0; border-radius: 5px;">
            <h3 style="color: ##4caf50; margin-top: 0;">✓ Registration Successful!</h3>
            <p>All fields have been validated successfully.</p>
        </div>
        
        <!--- Display submitted data --->
        <h3>Submitted Data</h3>
        <div style="background: white; border: 1px solid ##ddd; padding: 15px; border-radius: 5px;">
            <table style="width: 100%; border-collapse: collapse;">
                <thead>
                    <tr style="background: ##e0e0e0;">
                        <th style="padding: 10px; border: 1px solid ##ccc; text-align: left;">Field</th>
                        <th style="padding: 10px; border: 1px solid ##ccc; text-align: left;">Value</th>
                    </tr>
                </thead>
                <tbody>
                    <!--- Loop through submitted form data --->
                    <cfloop collection="#form#" item="key">
                        <cfif key NEQ "submitted" AND key NEQ "fieldnames">
                            <tr>
                                <td style="padding: 10px; border: 1px solid ##ccc;"><strong><cfoutput>#key#</cfoutput></strong></td>
                                <td style="padding: 10px; border: 1px solid ##ccc;"><cfoutput>#form[key]#</cfoutput></td>
                            </tr>
                        </cfif>
                    </cfloop>
                </tbody>
            </table>
        </div>
        
    <cfelse>
        
        <div style="background: ##ffebee; border: 2px solid ##f44336; padding: 20px; margin: 20px 0; border-radius: 5px;">
            <h3 style="color: ##f44336; margin-top: 0;">✗ Validation Failed</h3>
            <p>Please correct the following errors:</p>
            
            <ul style="margin: 15px 0; color: ##d32f2f;">
                <!--- Loop through validation errors --->
                <cfloop collection="#validationErrors#" item="fieldName">
                    <cfloop array="#validationErrors[fieldName]#" index="error">
                        <li style="margin: 5px 0;"><cfoutput><strong>#error#</strong></cfoutput></li>
                    </cfloop>
                </cfloop>
            </ul>
        </div>
        
        <!--- Display error details --->
        <h3>Error Details</h3>
        <div style="background: white; border: 1px solid ##ddd; padding: 15px; border-radius: 5px;">
            <table style="width: 100%; border-collapse: collapse;">
                <thead>
                    <tr style="background: ##e0e0e0;">
                        <th style="padding: 10px; border: 1px solid ##ccc; text-align: left;">Field</th>
                        <th style="padding: 10px; border: 1px solid ##ccc; text-align: left;">Errors</th>
                    </tr>
                </thead>
                <tbody>
                    <cfloop collection="#validationErrors#" item="fieldName">
                        <tr>
                            <td style="padding: 10px; border: 1px solid ##ccc;">
                                <strong><cfoutput>#validationRules[fieldName].label#</cfoutput></strong>
                            </td>
                            <td style="padding: 10px; border: 1px solid ##ccc;">
                                <ul style="margin: 0; padding-left: 20px;">
                                    <cfloop array="#validationErrors[fieldName]#" index="error">
                                        <li><cfoutput>#error#</cfoutput></li>
                                    </cfloop>
                                </ul>
                            </td>
                        </tr>
                    </cfloop>
                </tbody>
            </table>
        </div>
        
    </cfif>
    
    <!--- Validation Statistics --->
    <div style="background: ##f5f5f5; border: 1px solid ##ccc; padding: 15px; margin: 20px 0; border-radius: 5px;">
        <h3>Validation Statistics</h3>
        <cfscript>
            totalFields = structCount(validationRules);
            failedFields = structCount(validationErrors);
            passedFields = totalFields - failedFields;
            successRate = (passedFields / totalFields) * 100;
        </cfscript>
        
        <div style="display: flex; justify-content: space-around; margin: 20px 0;">
            <div style="text-align: center;">
                <div style="font-size: 36px; color: ##4caf50; font-weight: bold;">
                    <cfoutput>#passedFields#</cfoutput>
                </div>
                <div style="color: ##666;">Passed</div>
            </div>
            <div style="text-align: center;">
                <div style="font-size: 36px; color: ##f44336; font-weight: bold;">
                    <cfoutput>#failedFields#</cfoutput>
                </div>
                <div style="color: ##666;">Failed</div>
            </div>
            <div style="text-align: center;">
                <div style="font-size: 36px; color: ##2196f3; font-weight: bold;">
                    <cfoutput>#totalFields#</cfoutput>
                </div>
                <div style="color: ##666;">Total</div>
            </div>
        </div>
        
        <div style="text-align: center;">
            <strong>Success Rate:</strong> 
            <span style="font-size: 20px; color: #isFormValid ? '##4caf50' : '##f44336'#;">
                <cfoutput>#numberFormat(successRate, "0.0")#%</cfoutput>
            </span>
        </div>
    </div>
    
    <p>
        <a href="?" style="padding: 10px 20px; background: ##2196f3; color: white; text-decoration: none; border-radius: 5px; display: inline-block;">
            ← Back to Form
        </a>
    </p>
    
<cfelse>
    
    <!--- Display Registration Form --->
    <form method="post">
        <input type="hidden" name="submitted" value="true">
        
        <fieldset style="border: 2px solid ##ddd; padding: 20px; margin: 20px 0; border-radius: 5px;">
            <legend style="font-weight: bold; font-size: 18px; color: ##2196f3;">Personal Information</legend>
            
            <div style="margin: 15px 0;">
                <label for="firstName"><strong>First Name:</strong> <span style="color: red;">*</span></label><br>
                <input type="text" name="firstName" id="firstName" style="padding: 8px; width: 300px; border: 1px solid ##ccc; border-radius: 3px;">
            </div>
            
            <div style="margin: 15px 0;">
                <label for="lastName"><strong>Last Name:</strong> <span style="color: red;">*</span></label><br>
                <input type="text" name="lastName" id="lastName" style="padding: 8px; width: 300px; border: 1px solid ##ccc; border-radius: 3px;">
            </div>
            
            <div style="margin: 15px 0;">
                <label for="age"><strong>Age:</strong> <span style="color: red;">*</span></label><br>
                <input type="number" name="age" id="age" style="padding: 8px; width: 150px; border: 1px solid ##ccc; border-radius: 3px;">
                <span style="color: ##666; font-size: 12px;">(Must be 18 or older)</span>
            </div>
        </fieldset>
        
        <fieldset style="border: 2px solid ##ddd; padding: 20px; margin: 20px 0; border-radius: 5px;">
            <legend style="font-weight: bold; font-size: 18px; color: ##2196f3;">Contact Information</legend>
            
            <div style="margin: 15px 0;">
                <label for="email"><strong>Email Address:</strong> <span style="color: red;">*</span></label><br>
                <input type="email" name="email" id="email" style="padding: 8px; width: 300px; border: 1px solid ##ccc; border-radius: 3px;">
            </div>
            
            <div style="margin: 15px 0;">
                <label for="phone"><strong>Phone Number:</strong></label><br>
                <input type="tel" name="phone" id="phone" placeholder="1234567890" style="padding: 8px; width: 200px; border: 1px solid ##ccc; border-radius: 3px;">
                <span style="color: ##666; font-size: 12px;">(Optional, 10 digits)</span>
            </div>
            
            <div style="margin: 15px 0;">
                <label for="country"><strong>Country:</strong> <span style="color: red;">*</span></label><br>
                <select name="country" id="country" style="padding: 8px; width: 300px; border: 1px solid ##ccc; border-radius: 3px;">
                    <option value="">Select a country...</option>
                    <option value="USA">United States</option>
                    <option value="Canada">Canada</option>
                    <option value="UK">United Kingdom</option>
                    <option value="Australia">Australia</option>
                    <option value="Other">Other</option>
                </select>
            </div>
        </fieldset>
        
        <fieldset style="border: 2px solid ##ddd; padding: 20px; margin: 20px 0; border-radius: 5px;">
            <legend style="font-weight: bold; font-size: 18px; color: ##2196f3;">Agreement</legend>
            
            <div style="margin: 15px 0;">
                <label>
                    <input type="checkbox" name="terms" value="true">
                    <strong>I accept the Terms & Conditions</strong> <span style="color: red;">*</span>
                </label>
            </div>
        </fieldset>
        
        <div style="margin: 20px 0;">
            <button type="submit" style="padding: 15px 30px; background: ##4caf50; color: white; border: none; border-radius: 5px; cursor: pointer; font-size: 16px; font-weight: bold;">
                ✓ Register
            </button>
            <button type="reset" style="padding: 15px 30px; background: ##9e9e9e; color: white; border: none; border-radius: 5px; cursor: pointer; font-size: 16px; margin-left: 10px;">
                ↺ Reset
            </button>
        </div>
        
        <p style="color: ##666; font-size: 14px;">
            <span style="color: red;">*</span> Required fields
        </p>
    </form>
    
</cfif>

<!--- Display Validation Rules --->
<h3>Configured Validation Rules</h3>
<div style="background: white; border: 1px solid ##ddd; padding: 15px; border-radius: 5px;">
    <table style="width: 100%; border-collapse: collapse;">
        <thead>
            <tr style="background: ##e0e0e0;">
                <th style="padding: 10px; border: 1px solid ##ccc; text-align: left;">Field</th>
                <th style="padding: 10px; border: 1px solid ##ccc; text-align: center;">Required</th>
                <th style="padding: 10px; border: 1px solid ##ccc; text-align: left;">Type</th>
                <th style="padding: 10px; border: 1px solid ##ccc; text-align: left;">Rules</th>
            </tr>
        </thead>
        <tbody>
            <!--- Loop through validation rules struct --->
            <cfloop collection="#validationRules#" item="fieldName">
                <cfset rule = validationRules[fieldName]>
                <tr>
                    <td style="padding: 10px; border: 1px solid ##ccc;"><strong><cfoutput>#rule.label#</cfoutput></strong></td>
                    <td style="padding: 10px; border: 1px solid ##ccc; text-align: center;">
                        <cfoutput>
                            <span style="color: #rule.required ? '##f44336' : '##9e9e9e'#; font-weight: bold;">
                                #rule.required ? '✓' : '—'#
                            </span>
                        </cfoutput>
                    </td>
                    <td style="padding: 10px; border: 1px solid ##ccc;"><cfoutput>#rule.type#</cfoutput></td>
                    <td style="padding: 10px; border: 1px solid ##ccc;">
                        <cfoutput>
                            <cfif structKeyExists(rule, "minLength")>Min length: #rule.minLength#<br></cfif>
                            <cfif structKeyExists(rule, "min")>Min value: #rule.min#<br></cfif>
                            <cfif structKeyExists(rule, "max")>Max value: #rule.max#<br></cfif>
                            <cfif NOT structKeyExists(rule, "minLength") AND NOT structKeyExists(rule, "min") AND NOT structKeyExists(rule, "max")>
                                <em>Standard validation</em>
                            </cfif>
                        </cfoutput>
                    </td>
                </tr>
            </cfloop>
        </tbody>
    </table>
</div>

Share this page

Was this page helpful?
We're glad. Tell us how this page helped.
We're sorry. Can you tell us what didn't work for you?
Thank you for your feedback. Your response will help improve this page.

On this page