ColdFusion in Context: Redirect
Suppose you want to redirect the user to another page. Let's examine some of the ways to do this.
- You can use cflocation.
- You can use javascript "equivalents".
- javascript location replace
- javascript location href
- javascript top location href (to break out of frames)
- You can refresh to the desired page.
- You can use cfinclude.
- You can use self-submitting form driven by javascript.
- You can use a user-submitted form.
- You can tell the user to back up.
Try cflocation
The cflocation tag works well when you want to change pages without further communication (except perhaps a query variable in the url). Nothing else on the page is likely to get processed; although I usually follow this tag with a cfabort just in case. It's quick and doesn't need javascript. However, once the logic reaches this tag, nothing else gets processed, EVEN ITEMS ABOVE IT. When you remember that pages normally process in simultaneous pieces, this isn't so surprising. Because ColdFusion checks for and obeys this tag first, there isn't any wasted effort. However, if you wanted the user to see a message prior to redirect, even a javascript alert, you're out of luck. Because the page doesn't finish loading, it can't set cookies. It is as if you were never here.
Try Javascript "Equivalents"
Javascript location.replace('{new location'}) and location.href='{new location}' and (to break out of a frame) top.location.href='{new location}' act like the cflocation except that other items on the page can be processed. You may not want anything else to be processed, especially if the user should not be on this page in the first place. Further, if javascript is disabled, the user is stuck here unless you provide alternatives.
Try Refresh
You can refresh to the new page without javascript but with a short delay by using a meta refresh. (See a later example.) This may or may not provide enough time to perform such tasks as setting a cookie first. (Refreshing to the current page until the cookie is set will work.) The pause is noticeable and may be objectionable.
Try cfinclude
This is a good alternative for many purposes. Passing data to the page happens automatically. Javascript isn't needed. Activity prior to the include takes place, even if the include is subsequently aborted. However if you don't want this prior activity, you need a different choice. If you want to set a cookie before the include is done, you need a different choice. You haven't changed pages; you've just extended the current page.
Try a Form Submitted by Javascript
You can use javascript to submit a form without user intervention. Passing data is easy. You can even use javascript to set the action page and set form values prior to submission. This method works well as long as javascript is available.
Try a User-submitted Form
Having the user acknowledge a message and letting the acknowledgment button cause a form to bring the user to a new page is natural and doesn't require javascript. It does, however, require some thought so that the prompt looks good and doesn't have a lot of excess baggage around it (such as that is no longer pertinent that would load first if you hadn't planned ahead).
Try Telling the User to Back Up
Simply stopping the train with cfabort and having the user back up is a robust method of getting the user back on track. It's more reliable than playing with history through javascript, and users should be used to this navigation by now.
Demonstrate Them All
Put this code in work2.cfm. In each mode, you'll try to give the user a javascript message. Then, the selected mode will use a specific method to send the user home. The methods below correspond to the discussion above.
WORK2
<p>
<cfparam name="Mode" default="1">
<script language="javascript">
alert("bye, bye");
<cfset DateTime=now()>
</script>
<cfif Mode is "1">
<cflocation url="home.cfm">
<cfelseif Mode is "2A">
<script language="javascript">
location.replace('home.cfm');
</script>
<cfelseif Mode is "2B">
<script language="javascript">
document.location.href='home.cfm';
</script>
<cfelseif Mode is "2C">
<script language="javascript">
top.location.href='home.cfm';
</script>
<cfelseif Mode is "3">
<meta http-equiv="refresh" content="1 url=
home.cfm?Rand=<cfoutput>#DateTime#</cfoutput>">
<cfelseif Mode is "4">
<cfinclude template="home.cfm">
<cfelseif Mode is "5">
<form name="Stealth" method="post">
<input type="hidden" name="dummy" value="jello">
</form>
<script language="javascript">
top.document.bgColor="white";
top.document.fgColor="white";
document.Stealth.action='home.cfm';
document.Stealth.submit();
</script>
<cfelseif Mode is "6">
<form name="Shown" method="post" action="home.cfm">
We're done here.
<input type="submit" value="OK">
</form>
<cfelseif Mode is "7">
Press your back button to continue.
<cfabort>
</cfif>
Put this code in work.cfm. It tries to load the current time into a cookie, includes work2.cfm, and ends with a label identifying itself.
<cfcookie name="Time" value=#now()#>
<cfinclude template="work2.cfm">
WORK
<p>
Put this code in home.cfm. It identifies itself. It passes the current value of the cookie to a page variable, expires the cookie, and displays the value. It then lets you select one of the modes just discussed.
HOME<br>
<cfparam name="cookie.Time" default="not set">
<cfset Temp=cookie.Time>
<cfcookie name="cookie.Time" value="not set" expires="Now">
<cfoutput>Cookie Time is #Temp#</cfoutput>
<p>
<a href="work.cfm?Mode=1">Try cflocation</a><br>
<a href="work.cfm?Mode=2A">Try javascript location replace</a><br>
<a href="work.cfm?Mode=2B">Try javascript location href</a><br>
<a href="work.cfm?Mode=2C">Try javascript top location href</a><br>
<a href="work.cfm?Mode=3">Try meta refresh</a><br>
<a href="work.cfm?Mode=4">Try cfinclude</a><br>
<a href="work.cfm?Mode=5">Try a form submitted by javascript</a><br>
<a href="work.cfm?Mode=6">Try a form submitted by the user</a><br>
<a href="work.cfm?Mode=7">Try telling the user to back up</a>
Summary
Each method has its own strengths and weaknesses. As you probably already know, cflocation works too fast to set a cookie. In fact, it appears that you never leave home when you use this method. The cfinclude tag displays text you'd rather not see on the way back home. Unless you supplement the manual form with cfabort, you see the rest of the original page (work.cfm) before you get a chance to press the button. Notice that the remainder of the code on the calling page may execute after the code on the included page but before the redirect action, depending on the the method you choose. Get comfortable with the methods you use and look carefully at their behavior to be sure you make the the right choice for the right job. =Marty=