to answer the immediate question, you would need a submit button... otherwise the form won't ever do anything (unless you use javascript, as you mentioned).
Code:
<FORM ACTION="form.cfm" METHOD="Post">
<INPUT TYPE="Hidden" NAME="MyField" VALUE="1">
<INPUT TYPE="Submit" NAME="Submit" VALUE="Go back and try again">
</FORM>
But to answer your initial question, the way I've always handled something like this is, as you were starting to say, have the form_action page included in the form page:
form.cfm-
Code:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"[URL unfurl="true"]http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">[/URL]
<CFPARAM name="FORM.myField" default="">
<CFSET errorMessage = "">
<CFIF IsDefined("FORM.submit")>
<CFIF Len(Trim(FORM.myField)) GT 0>
<CFIF (ListLen("#FORM.myField#","@") EQ 2) AND (Find(".","#FORM.myField#") GT 0)>
<CFINCLUDE template="form_action.cfm">
<CFABORT>
</CFIF>
</CFIF>
<CFSET errorMessage = "<P><B>Form error:</B> you must enter a valid email address</P>">
</CFIF>
<html xmlns="[URL unfurl="true"]http://www.w3.org/1999/xhtml">[/URL]
<head>
<title>Form Validator</title>
<style>
.requiredLabel{
color : Red;
}
.wingdings{
font-family : Wingdings;
}
</style>
</head>
<body>
<b class="requiredLabel">Red</b> fields are required.<br />
<CFOUTPUT>
#errorMessage#
<form action="#GetFileFromPath(GetBaseTemplatePath())#" id="myForm" name="myForm" method="post">
<b class="requiredLabel">Enter your email address:</b><BR />
<CFIF Len(Trim(errorMessage)) GT 0><span class="wingdings"><span class="requiredLabel">è</span></span></CFIF> <input type="text" name="myField" id="myField" value="#FORM.myField#" />
<P><input type="submit" name="submit" id="submit" value="Go!" /></P>
</form>
</CFOUTPUT>
</body>
</html>
and
form_action.cfm-
Code:
<html xmlns="[URL unfurl="true"]http://www.w3.org/1999/xhtml">[/URL]
<head>
<title>Form Action Page</title>
</head>
<body>
Thank you for submitting the valid email address: <CFOUTPUT>#FORM.myField#</CFOUTPUT>!
</body>
</html>
A couple of things:
You could obviously just include the code for the action page directly in form.cfm, instead of doing a CFINCLUDE... but having them in separate files helps simplify maintenance, particularly if your form is complex.
Also, you could just use a CFELSE, rather than a CFABORT. Good programming practice says that you always refrain from using ABORTs or BREAKs or EXITs... but using a CFABORT in this case allowed me to put the entire IsDefined("FORM.submit"

block into a custom tag (with a little revision to genericize everything)... so I can share the same validation routines across the entire site.
Finally, doing a CFINCLUDE rather than a CFLOCATION allows the form_action.cfm page access to all the submitted form values. You could use CFLOCATION, but then you'd have to manually build a querystring with all the fieldnames and values. The drawback of using CFINCLUDE is that your URL doesn't chance when the form is submitted... which means your form_action.cfm page won't ever show up in your logs... which means if you run a tracking report with Webtrends or whatever, you won't have an accurate count of how many people actually submitted the form successfully.
Hope it helps,
-Carl