- CFML Reference User Guide
- ColdFusion functions
- ColdFusion functions by category
- Functions a-b
- Abs
- ACos
- AddSOAPRequestHeader
- AddSOAPResponseHeader
- AjaxLink
- AjaxOnLoad
- ApplicationStop
- ArrayAppend
- ArrayAvg
- ArrayClear
- ArrayContains
- ArrayContainsNoCase
- ArrayDelete
- ArrayDeleteAt
- ArrayDeleteNoCase
- ArrayEach
- ArrayFilter
- ArrayFind
- ArrayFindAll
- ArrayFindAllNoCase
- ArrayFindNoCase
- ArrayInsertAt
- ArrayIsDefined
- ArrayIsEmpty
- ArrayLen
- ArrayMap
- ArrayMax
- ArrayMin
- ArrayNew
- ArrayPrepend
- ArrayReduce
- ArrayResize
- ArraySet
- ArraySetMetadata
- ArraySlice
- ArraySort
- ArraySum
- ArraySwap
- ArrayToList
- Asc
- ASin
- Atn
- AuthenticatedContext
- AuthenticatedUser
- BinaryDecode
- BinaryEncode
- BitAnd
- BitMaskClear
- BitMaskRead
- BitMaskSet
- BitNot
- BitOr
- BitSHLN
- BitSHRN
- BitXor
- BooleanFormat
- Abs
- Functions-c-d
- CacheGet
- CacheGetAllIds
- CacheGetMetadata
- CacheGetProperties
- CacheGetSession
- CacheIdExists
- CachePut
- CacheRegionExists
- CacheRegionNew
- CacheRegionRemove
- CacheRemove
- CacheRemoveAll
- CacheSetProperties
- CallStackDump
- CallStackGet
- CanDeSerialize
- Canonicalize
- CanSerialize
- Ceiling
- CharsetDecode
- CharsetEncode
- Chr
- CJustify
- Compare
- CompareNoCase
- Cos
- CreateDate
- CreateDateTime
- CreateObject
- CreateObject: .NET object
- CreateObject: COM object
- CreateObject: component object
- CreateObject: CORBA object
- CreateObject: Java or EJB object
- CreateObject: web service object
- CreateODBCDate
- CreateODBCDateTime
- CreateODBCTime
- CreateSignedJWT
- CreateEncryptedJWT
- CreateTime
- CreateTimeSpan
- CreateUUID
- CSRFGenerateToken
- CSRFVerifyToken
- CSVRead
- CSVWrite
- CSVProcess
- DateAdd
- DateCompare
- DateConvert
- DateDiff
- DateFormat
- DatePart
- DateTimeFormat
- Day
- DayOfWeek
- DayOfWeekAsString
- DayOfYear
- DaysInMonth
- DaysInYear
- DE
- DecimalFormat
- DecodeForHTML
- DecodeFromURL
- DecrementValue
- Decrypt
- DecryptBinary
- DeleteClientVariable
- Deserialize
- DeserializeJSON
- DeserializeXML
- DirectoryCopy
- DirectoryCreate
- DirectoryDelete
- DirectoryExists
- DirectoryList
- DirectoryRename
- DollarFormat
- DotNetToCFType
- Duplicate
- Functions-e-g
- EncodeForCSS
- EncodeForDN
- EncodeForHTML
- EncodeForHTMLAttribute
- EncodeForJavaScript
- EncodeForLDAP
- EncodeForURL
- EncodeForXML
- EncodeForXMLAttribute
- EncodeForXpath
- Encrypt
- EncryptBinary
- EntityDelete
- EntityLoad
- EntityLoadByExample
- EntityLoadByPK
- EntityMerge
- EntityNew
- EntityReload
- EntitySave
- EntityToQuery
- Evaluate
- Exp
- ExpandPath
- FileClose
- FileCopy
- FileDelete
- FileExists
- FileGetMimeType
- FileIsEOF
- FileMove
- FileOpen
- FileRead
- FileReadBinary
- FileReadLine
- FileSeek
- FileSetAccessMode
- FileSetAttribute
- FileSetLastModified
- FileSkipBytes
- FileUpload
- FileUploadAll
- FileWrite
- FileWriteLine
- Find
- FindNoCase
- FindOneOf
- FirstDayOfMonth
- Fix
- Floor
- FormatBaseN
- GeneratePBKDFKey
- GenerateSecretKey
- GetApplicationMetadata
- GetAuthUser
- GetBaseTagData
- GetBaseTagList
- GetBaseTemplatePath
- GetClientVariablesList
- GetComponentMetaData
- GetContextRoot
- GetCPUUsage
- GetCurrentTemplatePath
- GetCSPNonce
- GetDirectoryFromPath
- GetEncoding
- GetException
- GetFileFromPath
- GetFileInfo
- GetFreeSpace
- GetFunctionCalledName
- GetFunctionList
- GetGatewayHelper
- GetHttpRequestData
- GetHttpTimeString
- GetK2ServerDocCount
- GetK2ServerDocCountLimit
- GetLocale
- GetLocaleDisplayName
- GetLocalHostIP
- GetMetaData
- GetMetricData
- GetPageContext
- GetPropertyString
- GetPropertyFile
- GetPrinterInfo
- GetPrinterList
- GetProfileSections
- GetProfileString
- GetReadableImageFormats
- GetSafeHTML
- GetSAMLAuthRequest
- GetSAMLLogoutRequest
- Generate3DesKey
- GenerateSAMLSPMetadata
- GetSOAPRequest
- GetSOAPRequestHeader
- GetSOAPResponse
- GetSOAPResponseHeader
- GetSystemFreeMemory
- GetSystemTotalMemory
- GetTempDirectory
- GetTempFile
- GetTemplatePath
- GetTickCount
- GetTimeZoneInfo
- GetToken
- GetTotalSpace
- GetUserRoles
- GetVFSMetaData
- GetWriteableImageFormats
- Functions-h-im
- Hash
- HMac
- Hour
- HQLMethods
- HTMLCodeFormat
- HTMLEditFormat
- IIf
- ImageAddBorder
- ImageBlur
- ImageClearRect
- ImageCopy
- ImageCreateCaptcha
- ImageCrop
- ImageDrawArc
- ImageDrawBeveledRect
- ImageDrawCubicCurve
- ImageDrawLine
- ImageDrawLines
- ImageDrawOval
- ImageDrawPoint
- ImageDrawQuadraticCurve
- ImageDrawRect
- ImageDrawRoundRect
- ImageDrawText
- ImageFlip
- ImageGetBlob
- ImageGetBufferedImage
- ImageGetEXIFMetadata
- ImageGetEXIFTag
- ImageGetHeight
- ImageGetIPTCMetadata
- ImageGetIPTCTag
- ImageGetMetadata
- ImageGetWidth
- ImageGrayscale
- ImageInfo
- ImageMakeColorTransparent
- ImageMakeTranslucent
- ImageNegative
- ImageNew
- ImageOverlay
- ImagePaste
- ImageRead
- ImageReadBase64
- ImageResize
- ImageRotate
- ImageRotateDrawingAxis
- ImageScaleToFit
- ImageSetAntialiasing
- ImageSetBackgroundColor
- ImageSetDrawingColor
- ImageSetDrawingStroke
- ImageSetDrawingTransparency
- ImageSharpen
- ImageShear
- ImageShearDrawingAxis
- ImageTranslate
- ImageTranslateDrawingAxis
- ImageWrite
- ImageWriteBase64
- ImageXORDrawingMode
- Functions-in-k
- IncrementValue
- InputBaseN
- Insert
- Int
- InterruptThread
- InvalidateOauthAccesstoken
- Invoke
- InitSAMLAuthRequest
- InitSAMLLogoutRequest
- InvokeCFClientFunction
- IsArray
- IsAuthenticated
- IsAuthorized
- IsBinary
- IsBoolean
- IsClosure
- IsCustomFunction
- IsDate
- IsDateObject
- IsDDX
- IsDebugMode
- IsDefined
- IsImage
- IsImageFile
- IsInstanceOf
- IsIPv6
- IsJSON
- IsK2ServerABroker
- IsK2ServerDocCountExceeded
- IsK2ServerOnline
- IsLeapYear
- IsLocalHost
- IsNull
- IsNumeric
- IsNumericDate
- IsObject
- isOnline
- IsPDFArchive
- IsPDFFile
- IsPDFObject
- IsProtected
- IsQuery
- isSamlLogoutResponse
- isSafeHTML
- IsSimpleValue
- IsSOAPRequest
- IsSpreadsheetFile
- IsSpreadsheetObject
- IsStruct
- isThreadInterrupted
- IsUserInAnyRole
- IsUserInRole
- IsUserLoggedIn
- IsValid
- IsValidOauthAccesstoken
- IsWDDX
- IsXML
- IsXmlAttribute
- IsXmlDoc
- IsXmlElem
- IsXmlNode
- IsXmlRoot
- JavaCast
- JSStringFormat
- Functions-l
- LCase
- Left
- Len
- ListAppend
- ListChangeDelims
- ListContains
- ListContainsNoCase
- ListDeleteAt
- ListEach
- ListFilter
- ListFind
- ListFindNoCase
- ListFirst
- ListGetAt
- ListGetDuplicates
- ListInsertAt
- ListLast
- ListLen
- ListMap
- ListPrepend
- ListQualify
- ListReduce
- ListRemoveDuplicates
- ListRest
- ListSetAt
- ListSort
- ListToArray
- ListValueCount
- ListValueCountNoCase
- LJustify
- Location
- Log
- Log10
- LSCurrencyFormat
- LSDateFormat
- LSDateTimeFormat
- LSEuroCurrencyFormat
- LSIsCurrency
- LSIsDate
- LSIsNumeric
- LSNumberFormat
- LSParseCurrency
- LSParseDateTime
- LSParseEuroCurrency
- LSParseNumber
- LSTimeFormat
- LTrim
- Functions-m-r
- Max
- Mid
- Min
- Minute
- Month
- MonthAsString
- Now
- NumberFormat
- ObjectEquals
- ObjectLoad
- ObjectSave
- OnWSAuthenticate
- ORMClearSession
- ORMCloseAllSessions
- ORMCloseSession
- ORMEvictCollection
- ORMEvictEntity
- ORMEvictQueries
- ORMExecuteQuery
- ORMFlush
- ORMFlushall
- ORMGetSession
- ORMGetSessionFactory
- ORMIndex
- ORMIndexPurge
- ORMReload
- ORMSearch
- ORMSearchOffline
- ParagraphFormat
- ParameterExists
- ParseDateTime
- Pi
- PrecisionEvaluate
- ProcessSAMLResponse
- ProcessSAMLLogoutRequest
- Quarter
- PreserveSingleQuotes
- QueryAddColumn
- QueryAddRow
- QueryConvertForGrid
- QueryExecute
- QueryFilter
- QueryGetResult
- QueryGetRow
- QueryKeyExists
- QueryMap
- QueryNew
- QueryReduce
- QuerySetCell
- QuotedValueList
- QueryEach
- Rand
- Randomize
- RandRange
- ReEscape
- REFind
- REFindNoCase
- ReleaseComObject
- REMatch
- REMatchNoCase
- RemoveCachedQuery
- RemoveChars
- RepeatString
- Replace
- ReplaceList
- ReplaceNoCase
- REReplace
- REReplaceNoCase
- RestDeleteApplication
- RestSetResponse
- RestInitApplication
- Reverse
- Right
- RJustify
- Round
- RTrim
- Functions-s
- Second
- SendGatewayMessage
- SendSAMLLogoutResponse
- Serialize
- SerializeJSON
- SerializeXML
- SessionInvalidate
- SessionRotate
- SessionGetMetaData
- SessionInvalidate
- SessionRotate
- SetDay
- SetEncoding
- SetHour
- SetLocale
- SetMonth
- SetProfileString
- SetPropertyString
- SetVariable
- SetYear
- Sgn
- Sin
- Sleep
- SpanExcluding
- SpanIncluding
- SpreadsheetAddAutoFilter
- SpreadsheetAddColumn
- SpreadsheetAddFreezePane
- SpreadsheetAddImage
- SpreadsheetAddInfo
- SpreadsheetAddPageBreaks
- SpreadsheetAddRow
- SpreadsheetAddRows
- SpreadsheetAddSplitPane
- SpreadsheetCreateSheet
- SpreadsheetDeleteColumn
- SpreadsheetDeleteColumns
- SpreadsheetDeleteRow
- SpreadsheetDeleteRows
- SpreadsheetFormatCell
- SpreadsheetFormatColumn
- SpreadsheetFormatCellRange
- SpreadsheetFormatColumn
- SpreadsheetFormatColumns
- SpreadsheetFormatRow
- SpreadsheetFormatRows
- SpreadsheetGetCellComment
- SpreadsheetGetCellFormula
- SpreadsheetGetCellValue
- SpreadsheetGetColumnCount
- SpreadsheetInfo
- SpreadsheetMergeCells
- SpreadsheetNew
- SpreadsheetRead
- SpreadsheetReadBinary
- SpreadsheetRemoveSheet
- SpreadsheetSetActiveSheet
- SpreadsheetSetActiveSheetNumber
- SpreadsheetSetCellComment
- SpreadsheetSetCellFormula
- SpreadsheetSetCellValue
- SpreadsheetSetColumnWidth
- SpreadsheetSetFooter
- SpreadsheetSetHeader
- SpreadsheetSetRowHeight
- SpreadsheetShiftColumns
- SpreadsheetShiftRows
- SpreadsheetWrite
- StreamingSpreadsheetNew
- StreamingSpreadsheetCleanup
- StreamingSpreadsheetRead
- StreamingSpreadsheetProcess
- SpreadsheetSetFooterImage
- SpreadsheetSetHeaderImage
- SpreadsheetSetFittoPage
- SpreadsheetUngroupColumns
- SpreadsheetGroupColumns
- SpreadsheetUngroupRows
- SpreadsheetGroupRows
- SpreadsheetRemoveColumnBreak
- SpreadsheetSetColumnBreak
- SpreadsheetRemoveRowBreak
- SpreadsheetSetRowBreak
- SpreadsheetRemovePrintGridlines
- SpreadsheetAddPrintGridlines
- SpreadsheetGetColumnWidth
- SpreadsheetSetColumnHidden
- SpreadsheetSetRowHidden
- SpreadsheetisColumnHidden
- SpreadsheetisRowHidden
- SpreadsheetisStreamingXmlFormat
- SpreadsheetisXmlFormat
- SpreadsheetisBinaryFormat
- SpreadsheetRenameSheet
- SpreadsheetRemoveSheetNumber
- SpreadsheetGetLastRowNumber
- SpreadsheetGetPrintOrientation
- Sqr
- StripCR
- StructAppend
- StructClear
- StructCopy
- StructCount
- StructDelete
- StructEach
- StructFilter
- StructFind
- StructFindKey
- StructFindValue
- StructGet
- StructGetMetadata
- StructInsert
- StructIsEmpty
- StructKeyArray
- StructKeyExists
- StructKeyList
- StructMap
- StructNew
- StructReduce
- StructSetMetadata
- StructSort
- StructToSorted
- StructUpdate
- StructValueArray
- StoreSetMetadata
- StoreGetACL
- StoreGetMetadata
- StoreAddACL
- StoreSetACL
- Functions-t-z
- Tan
- ThreadJoin
- ThreadTerminate
- Throw
- TimeFormat
- ToBase64
- ToBinary
- ToScript
- ToString
- Trace
- Transactionandconcurrency
- TransactionCommit
- TransactionRollback
- TransactionSetSavePoint
- Trim
- UCase
- URLDecode
- URLEncodedFormat
- URLSessionFormat
- Val
- ValueList
- VerifyClient
- Week
- Wrap
- WriteDump
- WriteLog
- WriteOutput
- WSGetAllChannels
- WSGetSubscribers
- WSPublish
- WSSendMessage
- XmlChildPos
- XmlElemNew
- XmlFormat
- XmlGetNodeType
- XmlNew
- XmlParse
- XmlSearch
- XmlTransform
- XmlValidate
- Year
- YesNoFormat
- ColdFusion tags
- ColdFusion tag summary
- ColdFusion tags by category
- Application framework tags
- Communications tags
- Database manipulation tags
- Data output tags
- Debugging tags
- Exception handling tags
- Extensibility tags
- File management tags
- Flow-control tags
- Forms tags
- Internet Protocol tags
- Page processing tags
- Security tags
- Variable manipulation tags
- Other tags
- Tags a-b
- Tags c
- cfcache
- cfcalendar
- cfcase
- cfcatch
- cfchart
- cfchart tag in ColdFusion
- Get started with cfchart
- Customize a chart using cfchart
- Advanced cfchart customization options
- Create an area chart in ColdFusion
- Create line charts in ColdFusion
- Create bar charts in ColdFusion
- Create floating bar charts in ColdFusion
- Create histograms in ColdFusion
- Create pie charts in ColdFusion
- Create funnel charts in ColdFusion
- Create pyramid charts in ColdFusion
- Create curve charts in ColdFusion
- Create boxplots in ColdFusion
- Create donut charts in ColdFusion
- Create bubble charts in ColdFusion
- Create scatterplots in ColdFusion
- Create radar charts in ColdFusion
- Other chart types in ColdFusion (Cone, Cylinder, Piano, and Bullet)
- Advanced customization options in cfchart
- cfchartdata
- cfchartseries
- cfchartset
- cfclient
- cfclientsettings
- cfcol
- cfcollection
- cfcomponent
- cfcontent
- cfcontinue
- cfcookie
- Tags f
- cffeed
- cffile
- cffile action = "append"
- cffile action = "copy"
- cffile action = "delete"
- cffile action = "move"
- cffile action = "read"
- cffile action = "readBinary"
- cffile action = "rename"
- cffile action = "upload"
- cffile action = "uploadAll"
- cffile action = "write"
- cffileupload
- cffinally
- cfflush
- cfform
- cfformgroup
- cfformitem
- cfftp
- cfftp: Connection: file and directory operations
- cfftp: Opening and closing FTP server connections
- cfftp : Opening and closing secure FTP server connections
- cfftp action = "listDir"
- cffunction
- Tags g-h
- Tags i
- Tags j-l
- cfjava
- cflayout
- cflayoutarea
- cfldap
- cflocation
- cflock
- cflog
- cflogin
- cfloginuser
- cflogout
- cfloop
- cfloop : conditional loop
- cfloop : index loop
- cfloop : looping over a COM collection or structure
- cfloop : looping over a date or time range
- cfloop : looping over a list, a file, or an array
- cfloop : looping over a query
- Tags m-o
- cfmail
- cfmailparam
- cfmailpart
- cfmap
- cfmapitem
- cfmediaplayer
- cfmenu
- cfmenuitem
- cfmessagebox
- cfmodule
- cfNTauthenticate
- cfoauth
- cfobject
- cfobject: .NET object
- cfobject: COM object
- cfobject: component object
- cfobject: CORBA object
- cfobject: Java or EJB object
- cfobject: web service object
- cfobjectcache
- cfoutput
- Tags p-q
- Tags r-s
- Tags t
- Tags u-z
- CFML Reference
- Reserved words and variables
- Ajax JavaScript functions
- Ajax JavaScript functions
- Function summary Ajax
- ColdFusion.Ajax.submitForm
- ColdFusion.Autosuggest.getAutosuggestObject
- ColdFusion.Layout.enableSourceBind
- ColdFusion.MessageBox.getMessageBoxObject
- ColdFusion.ProgressBar.getProgressBarObject
- ColdFusion.MessageBox.isMessageBoxDefined
- JavaScriptFunctionsinColdFusion9Update1
- ColdFusion ActionScript functions
- ColdFusion mobile functions
- Application.cfc reference
- Script functions implemented as CFCs
- ColdFusion Flash Form style reference
- Styles valid for all controls
- Styles for cfform
- Styles for cfformgroup with horizontal or vertical type attributes
- Styles for box-style cfformgroup elements
- Styles for cfformgroup with accordion type attribute
- Styles for cfformgroup with tabnavigator type attribute
- Styles for cfformitem with hrule or vrule type attributes
- Styles for cfinput with radio, checkbox, button, image, or submit type attributes
- Styles for cftextarea tag and cfinput with text, password, or hidden type attributes
- Styles for cfselect with size attribute value of 1
- Styles for cfselect with size attribute value greater than 1
- Styles for cfcalendar tag and cfinput with dateField type attribute
- Styles for the cfgrid tag
- Styles for the cftree tag
- ColdFusion Flash Form Style Reference
- ColdFusion event gateway reference
- ColdFusion Event Gateway reference
- addEvent
- CFEvent
- CFEventclass
- Constructor
- Gateway development interfaces and classes
- getStatus
- setCFCPath
- setCFCMethod
- getOriginatorID
- getLogger
- getBuddyList
- getBuddyInfo
- IM gateway message sending commands
- IM Gateway GatewayHelper class methods
- onIncomingMessage
- onIMServerMessage
- onBuddyStatus
- onAddBuddyResponse
- onAddBuddyRequest
- IM Gateway CFC incoming message methods
- IM gateway methods and commands
- CFML CFEvent structure
- warn
- info
- setOriginatorID
- data command
- submit Multi command
- submit command
- setGatewayType
- setGatewayID
- setData
- setCFCListeners
- outgoingMessage
- getStatusTimeStamp
- numberOfMessagesReceived
- numberOfMessagesSent
- removeBuddy
- removeDeny
- removePermit
- setNickName
- setPermitMode
- setStatus
- SMS Gateway CFEvent structure and commands
- SMS Gateway incoming message CFEvent structure
- getStatusAsString
- getProtocolName
- getPermitMode
- getPermitList
- getNickName
- getName
- getDenyList
- getCustomAwayMessage
- getQueueSize
- getMaxQueueSize
- getHelper
- getGatewayType
- getGatewayServices
- getGatewayID_1
- getGatewayID
- getData
- getCFCTimeout
- setCFCTimeout
- getCFCPath
- getCFCMethod
- GatewayServices class
- Gateway interface
- GatewayHelper interface
- addPermit
- addDeny
- addBuddy
- error
- debug
- Logger class
- stop
- start
- CFML event gateway SendGatewayMessage data parameter
- restart
- fatal
- SMS gateway message sending commands
- ColdFusion C++ CFX Reference
- ColdFusion Java CFX reference
- WDDX JavaScript Objects
- Cloud services
- ColdFusion and GCP Storage
- ColdFusion and GCP Firestore
- ColdFusion and GCP PubSub
- ColdFusion and Amazon S3
- ColdFusion and DynamoDB
- ColdFusion and Amazon SQS
- ColdFusion and Amazon SNS
- ColdFusion and MongoDB
- ColdFusion and Azure Blob
- ColdFusion and Azure Service Bus
- Multi-cloud storage services
- Multi-cloud RDS databases
- ColdFusion and Azure Cosmos DB
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
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>
<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
<!--- 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>

