One of the tools in the RadControls for ASP.NET AJAX suite that is getting a lot of attention these days is the RadInput control. More specifically, the RadInputManager. With this "Manager" control, you can easily add validation to any textbox on your page without littering your markup with ASP.NET validator controls. Plus, you'll get a much more dynamic validation experience when you use RadInput instead of the OTB (Out of The Box) ASP.NET validation controls and better page performance (since the manager enables you to save a lot of HTML and JavaScript).

One of the other features of the RadInput textboxes, including textboxes initialized by the RadInputManager, is their client-side API. Like most of the RadControls for ASP.NET AJAX, RadInput boasts a client-side API that is nearly identical to the server-side model. This enables us to create some very rich experiences when validating our users input. I decided to use the client-side API of RadInput with the client-side API of RadToolTip to enhance my input validation experience to automatically display a tool tip when my users make an input error. Let's see how it works...

THE SCENARIO

Let's say you have a form with a bunch of textboxes. Some of the textboxes should only accept numbers. Some only date information. Some only information that matches a RegEx pattern (like email). Wouldn't it be great if you could, A) automatically add validation to these textboxes, B) provide visual feedback when the users enter bad values (in real-time), and C) display a rich tool-tip if the users have trouble meeting your validation rules?

THE TOOLS

To solve this problem, you need a RadInputManager, a RadToolTipManager, and a few standard ASP.NET textbox controls. By using the Manager controls instead of individual RadInput or RadToolTip controls, our page will be highly optimized to handle 5 or 500 inputs. For today's test, though, here's what my simple test page looks like:

radinput_enterDetails

THE PROCESS

The first thing we need to do is add validation to our TextBox controls. That can be done using the RadInputManager, much in the way you may have used RadAjaxManager in the past to ajaxify your project. The InputManager has both a design-time wizard that makes configuration as easy as a few clicks and rich IntelliSense support for configuration via code. Whichever way you configure the RadInputManager, you'll end-up with the same markup. To support our scenario, the markup will look like this:

ASPX

<telerik:RadInputManager ID="RadInputManager1" runat="server"> <telerik:NumericTextBoxSetting MinValue="0" MaxValue="115"> <ClientEvents OnError="onClientNumTxtError" OnBlur="onClientTxtBlur" OnKeyPress="onClientTextChanged" /> <TargetControls> <telerik:TargetInput ControlID="txtAge" /> </TargetControls> </telerik:NumericTextBoxSetting> <telerik:DateInputSetting MinDate="1/1/1980" MaxDate="1/1/2020"> <ClientEvents OnError="onClientDateTxtError" OnKeyPress="onClientTextChanged" /> <TargetControls> <telerik:TargetInput ControlID="txtDate" /> </TargetControls> </telerik:DateInputSetting> <telerik:RegExpTextBoxSetting IsRequiredFields="true" ValidationExpression="^\w+([-+.']\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$"> <ClientEvents OnError="onClientRegTxtError" OnKeyPress="onClientTextChanged" /> <TargetControls> <telerik:TargetInput ControlID="txtEmail" /> </TargetControls> </telerik:RegExpTextBoxSetting> </telerik:RadInputManager>

A few things to note about this code:

  • We've defined 3 RadInput settings: 1 for numeric data, 1 for date data, 1 for RegEx data
  • For each, I've set the TargetControls collection to target the controls I want validated
  • For the numeric and date settings, I've set the Max and Min values the textboxes are allowed to receive (in effect, adding Range validation)
  • For each setting, I've wired-up some client-side events: OnError, OnKeyPress, and OnBlur (for numeric input)

 

With just these settings, my plain old ASPNET textboxes will already provide rich visual feedback and validation. I don't have to write any more code. Here's what the standard validation looks like:

radinput_defaultError

Notice that by default, only the RegEx textbox enables you do display an error message. The numeric and date inputs simply convey that the data is invalid (numeric data is checked real-time, so you cannot enter non-numeric values). Let's improve this default by adding ToolTips that are displayed when the RadInput OnError event is fired. For the real-time numeric input control, let's display our tip if the user triggers 3 errors (or in other words, the user tries 3 times to enter non-numeric values). We could display the tip on the first error, but we'll assume that one mistake doesn't warrant a ToolTip, but three mistakes means the user may be confused and need ToolTip help.

HANDLING ONERROR

To handle OnError, we'll need three separate JavaScript functions to handle the unique eventArgs for each type of RadInput control (Numeric, Date, RegEx). In these events, we'll use the supplied eventArgs to set the ToolTip's error message text and set the textbox element that the ToolTip should point to. For Numeric and Date data, we'll try to create a ToolTip that displays the max/min values allowed in the textbox (if these range values have been set), and for RegEx data, we'll simply display the error message defined for the control. When we do all of that, we end-up with some JavaScript like this:

JAVASCRIPT

var errorCount = 0; //Keep track of Numeric input errors var tooltipManager = null; //Ref to tooltipManager //Handles Numeric input errors (fires as user types error) function onClientNumTxtError(sender, args) {
    //Keep track of key errors //(Note: Numeric input fires OnError as // the user types if key is not numeric)
    errorCount += 1;
     
    //If user makes 3 errors, try to provide additional //assistance via a tooltip (they must be having trouble) if (errorCount > 2) {
        //Get DOM reference to textbox var eleId = args.get_targetInput().get_id();
        var ele = $get(eleId);
 
        //Try to get max/min setting for input control var max = sender.get_maxValue();
        var min = sender.get_minValue();
        var errMsg = "Value out of range";
         
        //If min or max value are set, try to customize error message if (max != null && min != null)
            errMsg = String.format("Value must be between {0} and {1}", min, max);
        else if (max != null && min == null)
            errMsg = String.format("Value may not be higher than {0}", max);
        else if (max == null && min != null)
            errMsg = String.format("Value may not be lower than {0}", min);
         
        //Show error tip
        showErrorTip(ele, errMsg);
    }
}
 
//Handles Date data input errors (fires on blur if input is invalid) function onClientDateTxtError(sender, args) {
    //Get DOM reference to textbox var eleId = args.get_targetInput().get_id();
    var ele = $get(eleId);
 
    //Try to get max/min date values allowed var max = sender.get_maxDate();
    var min = sender.get_minDate();
    var errMsg = "Date is out of range";
     
    //If min or max date are set, customize the error message if (max != null && min != null)
        errMsg = String.format("Date must be between {0} and {1}", min.format("d"), max.format("d"));
    else if (max != null && min == null)
        errMsg = String.format("Date must be on or before {0}", max.format("d"));
    else if (max == null && min != null)
        errMsg = String.format("Date must be on or after {0}", min.format("d"));
     
    //Show the error tip
    showErrorTip(ele, errMsg);
}
 
//Handles RegEx input errors (fires on blur if input is invalid) function onClientRegTxtError(sender, args) {
    //Get DOM reference to textbox var eleId = args.get_targetInput().get_id();
    var ele = $get(eleId);
     
    //Get error message from control var errMsg = sender.get_errorMessage();
    //Handle missing error message if (errMsg == null || errMsg == "")
        errMsg = "Invalid entry";
         
    //Show error message
    showErrorTip(ele, errMsg);
}
 

At the end of each of these methods, you see a call to "showErrorTip(ele, errMsg)." That is another function on the page that accepts an HTML DOM Element and a string message and then displays a RadToolTip with the supplied message attached to the supplied DOM element. To make this work, we first need a RadToolTipManager on the page:

ASPX

<telerik:RadToolTipManager ID="RadToolTipManager1" runat="server" Position="MiddleRight" RelativeTo="Element" AutoTooltipify="false" Skin="Hay" Animation="Fade" ShowEvent="FromCode" HideEvent="FromCode"> </telerik:RadToolTipManager>

Notice that I've set "ShowEvent" and "HideEvent" to "FromCode." This will ensure that tips are only displayed when we want to display them in our OnError processing. We've also set "AutoTooltipify" to false so that our RadInputManager won't try to add ToolTips to everything on the page automatically. With our RadToolTipManager set, next we need to write the JavaScript that will show the tips:

JAVASCRIPT

//Displays ToolTip with supplied message function showErrorTip(element, msg) {
    //Init tooltipmanager reference (if necessary) if (tooltipManager == null)
        tooltipManager = $find("<%= RadToolTipManager1.ClientID %>");
    //If the user hovers the image before the page has loaded, there is no manager created if (!tooltipManager) return;
 
    //Find the tooltip for this element if it has been created var tooltip = tooltipManager.getToolTipByElement(element);
 
    //Create a tooltip if no tooltip exists for such element if (!tooltip)
        tooltip = tooltipManager.createToolTip(element);
 
    //Set tooltip details
    tooltip.set_content(msg);
    tooltip.set_autoCloseDelay(5000);
    tooltip.show();                   
}

Here we simply get a reference to the RadToolTipManager client-side object, create a ToolTip for the supplied HTML element, set the Tip's contents, and then display it on the page (done via the "tooltip.show()" call). We could have also moved the "AutoCloseDelay" to the RadToolTipManager definition, but I've left it here so you can see that the ToolTip API gives you lots of control.

To hide the ToolTips, we'll handle the RadInput's OnKeyPress client event. This event fires- as the name implies- whenever a key is pressed in a RadInput control. In our event handler (which is the same for all of our input controls, regardless of type), we'll simply close any open RadTips when the user starts typing, like this:

JAVASCRIPT

//Handle the OnKeyPress event of RadInput function onClientTextChanged(sender, args) {
    //Hide any open tips on typing
    HideTooltip();
}
 
//Hides the open ToolTip (if there is one) function HideTooltip() {
    var tip = Telerik.Web.UI.RadToolTip.getCurrent();
    if (tip) tip.hide();
}

THE RESULT

With our JavaScript code in-place, we now get helpful ToolTips when the text we type is invalid. The tips disappear when we start typing again, but they be redisplayed if we make another input error. Plus, all of our standard RadInput validation and feedback continues to work, so we still get real-time (for numeric) and OnBlur style changes when invalid data is entered.

radinput_finishedValidation

THE CONCLUSION

With a little bit of JavaScript and the rich, client-side APIs from the RadControls at your disposal, you can create very dynamic and helpful form input validation. Remember, we did not add any standard ASP.NET validator controls to this page, nor did we add individual RadInput controls. Everything is dynamic. If your form had 100 inputs, as long as you add the target controls to the RadInputManager, this validation and the ToolTips would just work. That's the kind of easy programming that I like, and hopefully you'll find this solution helpful in your projects, too!

 


About the Author

Todd Anglin

is an avid HTML5, CSS3, and JavaScript advocate, and geek about all things web development. He is an active speaker and author, helping developers around the world learn and adopt HTML5. Todd works for Telerik as VP of HTML5 Web & Mobile Tools, where his current technical focus is on Kendo UI. Todd is @toddanglin on Twitter

Related Posts

Comments

Comments are disabled in preview mode.