asp tutorials, asp.net tutorials, sample code, and Microsoft news from 15Seconds
Data Access  |   Troubleshooting  |   Security  |   Performance  |   ADSI  |   Upload  |   Email  |   Control Building  |   Component Building  |   Forms  |   XML  |   Web Services  |   ASP.NET  |   .NET Features  |   .NET 2.0  |   App Development  |   App Architecture  |   IIS  |   Wireless
 
Pioneering Active Server
 Power Search





Active News
15 Seconds Weekly Newsletter
• Complete Coverage
• Site Updates
• Upcoming Features

More Free Newsletters
Reference
News
Articles
Archive
Writers
Code Samples
Components
Tools
FAQ
Feedback
Books
Links
DL Archives
Community
Messageboard
List Servers
Mailing List
WebHosts
Consultants
Tech Jobs
15 Seconds
Home
Site Map
Press
Legal
Privacy Policy
internet.commerce














internet.com
IT
Developer
Internet News
Small Business
Personal Technology
International

Search internet.com
Advertise
Corporate Info
Newsletters
Tech Jobs
E-mail Offers

HardwareCentral
Compare products, prices, and stores at Hardware Central!

Reusable Mobile Forms
By Eric Barr
Rating: 2.4 out of 5
Rate this article


  • email this article to a colleague
  • suggest an article

    Introduction

    One of the goals of our site and many other personalized Web sites is to gather as much information about a user as possible. Not only does this allow the site to be customized for the user, a main component of making your site "stickier," it also gives your company a valuable asset: the data. But on the other hand, users are often scared away from a site that asks them to enter too much data before they can begin using its features.

    In order to acquire personal data on an as-needed basis, a site can request users to enter specific data "just-in-time," meaning right when they attempt to use features that depend on that data. Not only does this break up their personal data entry into smaller, less-intimidating forms, it also makes it clear why the data is being requested, so they won’t be as reluctant to provide it. But if several features require the same piece(s) of data, a mechanism is needed to display and process the same form on different Web pages without duplicating the same code everywhere. This is the main idea of "Mobile Forms."

    Side Benefit

    Processing HTML forms can result in ugly Active Server Page script code. When posting a form to the same ASP page on which it is displayed (a common practice), script code for processing the form often becomes intertwined with the code for displaying it. It soon becomes difficult to follow the execution path to determine what gets displayed in different cases, such as the following:

    • when there is an error on the form,
    • when the form is submitted successfully,
    • or when the form hasn’t been submitted yet.
    This complexity can be greatly reduced by encapsulating form display and form processing in separate server-side functions. As when using functions in any language, not only do the functions make the form code more readable, they also make the form code more reusable, or mobile.

    General Form Order

    Although it is possible to show and process the form on separate pages, it is still nice to keep everything related to the form in the same file. So before we look at the sample code, let’s look at the execution flow of a typical page with a form on it. It usually goes a little something like this:

    1. Check if the form was submitted.
    2. If form is submitted,
      1. do any server-side validation and display errors, if any.
      2. if no errors, take some special action (display success message and end response, or redirect, or redisplay answers, etc.).
    3. If form wasn’t submitted, display the form.

    To the Example Code

    Now let’s look at a simple ASP page that displays a logon form and processes it with some validation. A logon form is a form that is easy to imagine being displayed on multiple pages, like when a user tries to access an area of the site that is available to members only. (The following examples use JScript, but of course it makes no difference which scripting language you use).

    
    <%@ LANGUAGE="JSCRIPT" %>
    <html>
    <head>
    	<title>Form example</title>
    </head>
    
    <body>
    <%
    	// Process a logon form, which may have been submitted
    	if (Request.Form("LoginFormSubmitFlag") == "true") {
    		var name	= new String(Request.Form("user"));
    		var pwd		= new String(Request.Form("password"));
    		if ((name == "ASPUser") && (pwd == "password")) {
    			Session("user") = name;
    			Response.Write("Welcome " + name);
    			Response.End();
    		} else {
    			// Nobody found with that name and password
    			Response.Write("Sorry.  Logon failed. ");
    			Response.Write("Please check your spelling and try again.");
    		}
    	}
    	
    %>
    <form name="LoginForm" method="post">
    <table>
    	<tr><td>User name:</td><td><input name="user" type="text" maxlength="16"></td>
    	</tr><tr><td>Password:</td><td><input name="password" type="password" maxlength="16"></td>
    	</tr><tr><td></td><td><input type="button" value="Enter" onclick="CheckLogin()"></td>
    	</tr>
    </table>
    <input type="hidden" name="LoginFormSubmitFlag" value="true">
    </form>
    <SCRIPT>
    function CheckLogin() {
    	if ((document.LoginForm.user.value == "") || (document.LoginForm.password.value == ""))
    		alert("You must enter a name and password to log on.");
    	else
    		document.LoginForm.submit();
    }
    </script>
    
    </body>
    </html>
    
    
    This still isn’t terribly ugly, but if you add several more fields and maybe even make it a multipage form, then it can get messy fast.

    ShowTheForm()

    Now let’s start breaking this code up, starting with showing the login form

    
    function ShowLoginForm() {
    %>
    <form name="LoginForm" method="post">
    <table>
    	<tr><td>User name:</td><td><input name="user" type="text" maxlength="16"></td>
    	</tr><tr><td>Password:</td><td><input name="password" type="password" maxlength="16"></td>
    	</tr><tr><td></td><td><input type="button" value="Enter" onclick="CheckLogin()"></td>
    	</tr>
    </table>
    <input type="hidden" name="LoginFormSubmitFlag" value="true">
    </form>
    <script>
    function CheckLogin() {
    	if ((document.LoginForm.user.value == "") || (document.LoginForm.password.value == ""))
    		alert("You must enter a name and password to log on.");
    	else
    		document.LoginForm.submit();
    }
    </script>
    <%
    }
    
    
    One of the most important things here is to make the form code completely self-contained. If all the tags aren’t matched, or if the function depends on being inside of a table with a certain number of columns, then the function isn’t very reusable. But if you put the form in its own table, then you can just plop that table into the body of any document or a cell of any other table. It’s easy to set up your form in this way if you do it like that from the start, but if your form is already written and shares a table used by your navigation layout or other elements of your page, it may be a little tricky to pull it out. (By the way, apparently the form tag should go on the outside of the table tags. Otherwise my HTML validator tells me "The tag: ‘FORM’ is not allowed within: ‘TABLE’ It is only allowed within: CENTER, DIV, TD, TH." But it seems to work fine either way.)

    Another thing that makes it easy to move the forms around is not specifying the action attribute. By not specifying the page to which you want to POST, the page defaults to posting to itself. This is exactly the behavior we want because it allows us to call the function on any page and have it work properly. If you would like to specify the action attribute for style reasons, or if there is a browser-compatibility issue that I may not know about, you could always construct the URL by using the SERVER_NAME, SCRIPT_NAME, and QUERY_STRING server variables.

    The last thing to notice in this form is the hidden input field, "LogonFormSubmitFlag." This flag is used to indicate the presence of submitted form data. There are a few reasons for using a hidden field instead of checking for the existence of a different form field. The main one is that visible form fields often change or disappear as product requirements change. It’s easy to delete a field or change its name and forget that that was the field you were using to check for posted data. Using the submit field works a little better than the others since it’s less likely to be removed, but if you change its value (the string displayed on the page), then you still have to change your processing code. Or, if you use an input of type "button" instead of "submit" that calls a JavaScript function for client-side validation, then the button type doesn’t submit its own name and value like an input of type "submit" does, so that won’t work either. A hidden field is a lot easier to keep around unchanged. And lastly, if you’re sure to give your hidden field a unique name, you can keep it from conflicting with other forms that you might later decide to place on the same page.

    We’ll see right away where the use of "LogonFormSubmitFlag" comes in.

    ProcessTheForm()

    The other function that we need to complement ShowLoginForm() is ProcessLoginForm(). Here it is:

    
    function ProcessLoginForm() {
    	if (Request.Form("LoginFormSubmitFlag") == "true") {
    		var name	= new String(Request.Form("user"));
    		var pwd		= new String(Request.Form("password"));
    		if ((name == "ASPUser") && (pwd == "password")) {
    			Session("user") = name;
    			return true;
    		} else {
    			// Nobody found with that name and password
    			Response.Write("Sorry.  Logon failed. ");
    			Response.Write("Please check your spelling and try again.");
    			return false;
    		}
    	}
    }
    
    
    The very first thing we do in ProcessLoginForm is see if the form has actually been submitted using the LogonFormSubmitFlag described above. If no data was submitted, the value of the variable will be undefined, so the test fails and we can return false right away. If data has been submitted, we can process it on the server side and return true. (Checking for the value set in the ShowLoginForm() function may seem like a dangerous situation since we must be sure to use the same value in both functions. However, since they will both reside in the same include file and the value is hidden and arbitrary anyway, I don’t consider it to be much of a risk.)

    Putting Them Together

    Now that we have the form divided up into the two pieces, if we put both of these functions in an include file called LoginFormInc.asp, then we can reduce the code on our main ASP page to the following:

    
    <%@ LANGUAGE="JSCRIPT" %>
    <!-- #include file="Include\LoginFormInc.asp" -->
    <html>
    <head>
    	<title>Form Test</title>
    </head>
    
    <body>
    <%
    	if (ProcessLoginForm())
    		// form was successfully submitted
    		Response.Write("Welcome " + Session("user"));
    	else
    		ShowLoginForm();
    %>
    </body>
    </html>
    
    
    Not only does it look a lot better, but now we have a login form that we can show and process on any page on our site.

    Error Reporting

    The last piece of this structure is error reporting in cases of failed server-side validation. Even with the JavaScript routines for client-side validation, we still do the same checks on the server side. This is for security reasons, just in case someone was to alter the original Web page and remove the client-side checks. This may seem wasteful or overly cautious, but there are other server-side errors that can arise that can’t be checked on the client side, such as failed logins or other failed database lookups.

    This is handled with a Session variable called Session("FormError"). It works in a manner similar to Microsoft’s GetLastError() routine. The function is returning a return code that is not the error code (in our case it is just a Boolean), but an error code is set before the return. Then the calling procedure can check for the error and display it if there is one.

    There are a few advantages to this. One is that you don’t have to Response.Write() the error immediately upon detection. That means you have more flexibility in where to place your ProcessTheForm() routine. The second is that by using the same procedure to handle your errors for every form, you can display form errors in a consistent place and/or style across all pages of your site. That makes it easier for the user to detect if there was a problem with the form or if it was submitted successfully. And this centralized data reporting gives you the chance to internally log the error somehow if you want, like to a file or a database.

    Again, let’s look at an example, modifying ProcessLoginForm() above:

    
    function ProcessLoginForm() {
    	if (Request.Form("LoginFormSubmitFlag") == "true") {
    		var name	= new String(Request.Form("user"));
    		var pwd		= new String(Request.Form("password"));
    	if ((name == "") || (pwd == "")) {
    		Session("FormError") = "You must enter a name and password to log on.";
    		return false;
    	}
    		if ((name == "ASPUser") && (pwd == "password")) {
    			Session("user") = name;
    			return true;
    		} else {
    			// Nobody found with that name and password
    			Session("FormError") = "Sorry.  Logon failed. Please check your spelling and try again.";
    			return false;
    		}
    	}
    }
    
    
    Then to handle these form errors, I call the same routine, ShowFormErrorOnPage(), at the top of any page that contains a form that can report errors. I put ShowFormErrorOnPage() in an include file called ErrorHandlingInc.asp, and it looks like this:
    
    function ShowFormErrorOnPage() {
    	if (Session("FormError") != "") {
    		Response.Write("<P><B><font color=\"red\">" + Session("FormError") + "</font></b><P>");
    		Session("FormError") = "";
    	}
    }
    
    
    Just be sure to call ShowFormErrorOnPage after you ProcessTheForm() so that any errors will get displayed. Also be sure to initialize Session("FormError") to "" in your Session_OnStart();

    Conclusion

    Of course, there are some enhancements that can be made to these routines. You may want to modify the ShowTheForm() code to redisplay submitted values after a failed process. Or you may want to return any actual error strings from ProcessTheForm() instead of a Boolean and skip the whole Session("FormError") part. But either way, the simple act of encapsulating the two basic tasks of showing and processing a form in server-side functions has great benefits. You don’t even have to have a need for moving your forms around in order to use this architecture. I’ve grown to like it as much for the code readability issue as the reusability. Hopefully either their mobility or legibility will make them useful to you.

    About the Author

    Eric Barr is the lead Web-application developer at LifeMasters Supported SelfCare, http://www.lifemasters.net, in south San Francisco. He has been programming with Active Server Pages full time for over two years, producing Intranet sites for nurses and Internet sites for their patients. LifeMasters’ new ASP-based site, http://www.lifemastersonline.com, helps patients learn about and manage their chronic diseases. Eric is also a skilled Pokemon trainer.

  • Rate This Article
    Not HelpfulMost Helpful
    1 2 3 4 5
    Other Articles
    Aug 7, 2002 - Using MySQL in the Win32 Environment
    Developers who don't want to spend a lot of money on SQL Server and who want a database that's more robust than Access may find MySQL to be a pleasant alternative. This introductory article covers the bare essentials for getting MySQL installed and running in the Win32 environment.
    [Read This Article]  [Top]
    Jul 17, 2002 - Software Development: Steps To Better Ensure Success
    There is never a guarantee of project success when endeavoring to build a sophisticated application. However, there are established steps to follow that will ensure a clear, concise scope, support for the team involved, and a solid opportunity for successful deployment.
    [Read This Article]  [Top]
    Jul 15, 2002 - Securing SQL Server for Web Applications
    If your SQL Server is exposed to the Internet, then hackers are probing it. This article shows how to secure a SQL Server database that's being used with a Web application
    [Read This Article]  [Top]
    Jul 1, 2002 - Protecting Your Web Application Against Dangerous Requests
    Enrico Di Cesare provides a solution for hiding and securing querystring values that pass through a url.
    [Read This Article]  [Top]
    Apr 2, 2002 - Object-Oriented Programming for VBScripters
    Feel intimidated by .NET? This article by Rob Chartier is designed to ease any level VBScripter (ASP) into .NET by clarifying some OOP concepts.
    [Read This Article]  [Top]
    Mar 27, 2002 - A Best Practice for Using ADO Objects
    A few members of the 15 Seconds discussion list talk about the proper way to use methods in order to prevent ADO object errors.
    [Read This Article]  [Top]
    Jan 2, 2002 - The ASP.NET Page Life Cycle
    Solomon Shaffer explores the life cycle of an ASP.NET page from initialization to unloading. He also explains the various methods to override ASP.NET server-side events.
    [Read This Article]  [Top]
    Dec 19, 2001 - Application Architecture: An N-Tier Approach - Part 2
    Rob Chartier creates a simple portable and reusable address book in .NET to demonstrate the power of N-tier application architecture. Complete source code included!
    [Read This Article]  [Top]
    Oct 23, 2001 - Application Architecture: An N-Tier Approach - Part 1
    Learn about N-tier application architecture and realize that developing with multiple layers produces a flexible and reusable application for distribution to any number of client interfaces.
    [Read This Article]  [Top]
    Oct 23, 2001 - Application Architecture: An N-Tier Approach - Part 1
    Learn about N-tier application architecture and realize that developing with multiple layers produces a flexible and reusable application for distribution to any number of client interfaces.
    [Read This Article]  [Top]
    Mailing List
    Want to receive email when the next article is published? Just Click Here to sign up.

    Support the Active Server Industry



    JupiterOnlineMedia

    internet.comearthweb.comDevx.commediabistro.comGraphics.com

    Search:

    Jupitermedia Corporation has two divisions: Jupiterimages and JupiterOnlineMedia

    Jupitermedia Corporate Info


    Legal Notices, Licensing, Reprints, & Permissions, Privacy Policy.

    Advertise | Newsletters | Tech Jobs | Shopping | E-mail Offers