After plugging reCAPTCHA into the contact Web Form, I got to thinking about how I don't really make clear that users may use the "From" field in a few different ways: They can ignore it altogether (use is optional); they may add an e-mail address, which is a great idea if one wants me to reply; or, they may add pretty much whatever else they want. The point I wanted to drive home was that of the e-mail address: that if one wants me to reply, one must indicate a means for doing so. ============== BUSINESS RULES ============== One some levels it seems completely asinine that I should have to spell this out for any Netizen. On others, however, it makes good design sense. So, the business rules for such a thing shape up like this: * A user may choose to type something into the "From" field * If the user desires me to reply, then populating that field with an e-mail address is a smart choice We don't have much here in the way of "requirements." I guess the only requirement here is that the field remain optional. It's a deceptively big requirement. This means that using a .NET validator control is not an option. Validators all interconnect, and bubble up to the Page object. Put simply, if the user was to enter something other than an e-mail address in that field, the validator would return false, making Page.IsValid() also return false, and the user would be unable to submit the form, even though she followed the rules. No, we have to go about this another way. That other way, in this case, is to validate the field using JavaScript methods apart from the .NET validators. ===================== DESIGN CONSIDERATIONS ===================== From a design perspective, here are the things we should consider: * We might consider placing a prompt inside the field, and use JavaScript to control display based on what the user is doing -- make it disappear when the user is typing in the field, make it appear when there is no user input in the field. * If a prompt is used inside the field, it shouldn't look like the field has been filled in for the user in advance. It should convey a message that obviously suggests direction. The code that makes it appear and disappear should help with this. * Because the field is optional, any validator-type prompt we provide should differ in appearance from the standard validator prompts. Validator prompts signify a problem with the user's input. In this case, there is no such problem. * Validator prompts are generally red in color -- so let's not use red * Validator prompts are generally worded rather directly; e.g., "This is a required field", "You must use letters and numbers ONLY", etc. Let's word our prompt less harshly to help with the idea that the user hasn't done anything against the business rules. Perhaps also consider placing the prompt in parenthesis as well. * We've been focusing on a validator prompt that is intended to encourage the user to enter a valid e-mail address in the field. We might also put some thought into a prompt to display if the user has done so. * We might also gain some advantage from knowing in the code behind whether the user has entered a valid e-mail address; we might use that string as the value for the mail object's "Reply-To" property. * All of this validator prompt talk implies we might want to actually VALIDATE the input of the field to determine whether the input actually IS a valid e-mail address Much to think about there -- maybe more than was expected. ============== IMPLEMENTATION ============== As an experiment, I decided to with both types of prompts: one inside the field as well as a prompt that appears outside of the field that acts more like a validator. The inside-the-field prompt I chose for this is: "«reply-to-me@my-email.com»". It is in the form of an e-mail address, and uses text that strongly suggests the user should place his addy here; this is obviously not a real e-mail address. The angle quotes (HTML: « and ») help convey that idea. Recall that we'll be controlling its appearance and disappearance, so once a user clicks on the field, the prompt will clear, leaving the user free to type anything she desires. The validator prompt I chose for this case is: "(Include a valid e-mail address if you'd like a response.)" And the color I chose for it is the standard black. I thought about using green, but, as the logical opposite of red, it's too encouraging; too easily interpreted as "You got it right! Good job!!" when really all I want to do is tell the user, "you know, you can leave me an e-mail address if you want to." I selected a second validator prompt for the case when the user has entered a valid e-mail address in the field. It simply reads, "This is a valid e-mail address." It is also in standard black, like the former, and for the same reasons. Our technology of choice here is JavaScript. Because it is client-resident, it can detect events that happen in the form and respond to them. In this case, we need prompts to appear and disappear based on the focus and blur of our "From" field. I wrote six functions to do the job for us -- one to populate the field with our prompt, one to clear the field of our prompt, and one to validate the user entry against a regular expression designed for well-formed e-mail addresses (called validateEmail()). One sets a flag for the codebehind and another sets the value of the validator prompt -- those two take the output from validateEmail() as their inputs. Finally, a controller that governs those interactions. The textbox on the form looks like this: Note that the Text property is populated with the value we're using for our in-field prompt. If this wasn't here, the prompt wouldn't appear when the form first loads. Also note that the events we're using are OnFocus and OnBlur. We're calling the clearField() function when the user puts focus on the field (i.e., clicks on it) -- function clearField() { var field = document.forms[0].ctl00$ContentPlaceHolder1$txtFrom; //default string must match the Text value in the control! var str = "«reply-to-me@my-email.com»"; //if the field contains our default string, empty the field if (field.value==str){ field.value=""; } } ..., and populateField() when the user shifts focus away from the field (i.e., tabs to the next field). function populateField() { var field = document.forms[0].ctl00$ContentPlaceHolder1$txtFrom; //default string must match the Text value in the control! var str = "«reply-to-me@my-email.com»"; //if the field is empty, populate it with our default string //and clear the value in the validator prompt if (field.value==""){ field.value=str; document.getElementById("divEmailWarn").innerHTML = ""; } else //otherwise, call our validator below { validationController(); } } A couple of notes about populateField(). Notice that if the field is empty, it populates the field with our default string and also clears the text in the div we're using as our validator prompt, "divEmailWarn". Also notice that if the field is not empty, it calls validationController(): function validationController() { var IsValid = validateEmail(); setIsValidFlag(IsValid); setValidatorPrompt(IsValid); } The controller calls validateEmail(), which reports back a Boolean describing whether the field input was or was not a valid e-mail address: function validateEmail() { var addr = document.forms[0].ctl00$ContentPlaceHolder1$txtFrom.value; var filter = /^([A-Za-z0-9_\-\.])+\@([A-Za-z0-9_\-\.])+\.([A-Za-z]{2,4})$/; //checks the e-mail addy against the regex if(filter.test(addr) == false) { return false; } else { return true; } } Back up at the controller, it sends this return value to setValidatorPrompt() and to setIsValidFlag(): function setValidatorPrompt(IsValid) { var field = document.getElementById("divEmailWarn"); //populates the inner HTML of a div in response to whether the "From" field //input is a valid e-mail address. //I used this instead of a .NET validator because the "from" field //is optional -- so this is more of an informational message. if(IsValid == true) { field.innerHTML = "This is a valid e-mail address."; } else { field.innerHTML = "(Include a valid e-mail address if you'd like a response.)"; } } function setIsValidFlag(IsValid) { var field = document.forms[0].ctl00$ContentPlaceHolder1$fldFromIsValidAddress; if(IsValid == true) { //plant a flag in a hidden field to signify the "From" field contains a valid e-mail address. //we'll use this value to signal the codebehind to use this addy as a Reply-To value in the message field.value="1"; } else { //erase the "valid address" flag if it exists field.value = ""; } } That hidden input satisfies the design consideration about giving the code behind a way to know if the field input is a valid e-mail address. Here's what happens under the covers: 'if the form evaluates the "from" field and determines 'it is a valid e-mail address, use it as a Reply-To addy If Me.fldFromIsValidAddress.Value = "1" Then blnFromIsValidAddress = True 'create MailAddress object for use below adrReplyTo = New MailAddress(strFrom) End If . . . (later, when creating the message object) . . . If blnFromIsValidAddress AndAlso adrReplyTo.ToString.Length > 0 Then .ReplyTo = adrReplyTo End If And when that message comes in, clicking "Reply" populates that address in the "To:" field. Sweet! ~~~~~ That should be it for now! Contact me using the site's contact form if you have questions (and see the cool new stuff!). Feel free to use the code in your projects. A shout out in your project would be thoughtful. Also, drop me a line and let me know how you might have tweaked things to better suit your needs. Finally, I wouldn't profess to be THE expert on matters represented in my code -- so drop me a line if you have constructive suggestions, too. (Particularly with JavaScript, I could use them!!) I'd like to hear from you! Best, halfgk Copyright 2010 halfgk.com