Tooltip

Ever wanted to use tooltips to display your errors? No? Maybe it's just me... Anyway, if you want to do it it's not that hard and here's the recipe. (And yes I know that this has nothing really to do with jQuery Validation Unobtrusive Native but it's kind of cool and interesting so there you go.)

Everything you need to see is in the JavaScript tab below. You can see that I'm using the Bootstrap Tooltip. That's because this is (in case you hadn't guessed) a Bootstrapped site. But the principal stands and you can use whatever tooltip loveliness you like really. Plug and play.

Here's the model, nothing special to report but we've got some Required attributes in place and one of the properties is a nullable integer which means we'll requiring a number:

    using System.ComponentModel.DataAnnotations;

    namespace jQuery.Validation.Unobtrusive.Native.Demos.Models
    {
        public class TooltipModel
        {
            [Required]
            public int? TextBox { get; set; }

            [Required]
            public string DropDownList { get; set; }
        }
    }
        

Here's the view (which uses the model):

    @model jQuery.Validation.Unobtrusive.Native.Demos.Models.RequiredModel
    @using (Html.BeginForm())
    {
        <div class="row">
            @Html.LabelFor(x => x.TextBox, "A number must be entered:")
            @Html.TextBoxFor(x => x.TextBox, true)
        </div>

        <div class="row">
            @Html.LabelFor(x => x.DropDownList, "An option must be selected:")
            @Html.DropDownListFor(x => x.DropDownList, true, new List<SelectListItem> {
                new SelectListItem{ Text = "Please select", Value = "" },
                new SelectListItem{ Text = "An option", Value = "An option"}
            })
        </div>

        <div class="row">
            <button type="submit" class="btn btn-default">Submit</button>
            <button type="reset" class="btn btn-info">Reset</button>
        </div>
    }
        

Here's the HTML that the view generates:

    <form action="/Demo/Tooltip" method="post">
        <div class="row">
            <label for="TextBox">A number must be entered:</label>
            <input data-msg-number="The field TextBox must be a number." 
                data-msg-required="The TextBox field is required." 
                data-rule-number="true" 
                data-rule-required="true" 
                id="TextBox" name="TextBox" type="text" value="" />
        </div>
        <div class="row">
            <label for="DropDownList">An option must be selected:</label>
            <select data-msg-required="The DropDownList field is required." 
                data-rule-required="true" 
                id="DropDownList" name="DropDownList">
                <option value="">Please select</option>
                <option value="An option">An option</option>
            </select>
        </div>
        <div class="row">
            <button type="submit" class="btn btn-default">Submit</button>
            <button type="reset" class="btn btn-info">Reset</button>
        </div>
    </form>
        

The showErrors option here does all the hard work of setting up our tooltips.

  $("form").validate({
          
      showErrors: function(errorMap, errorList) {

          // Clean up any tooltips for valid elements
          $.each(this.validElements(), function (index, element) {
              var $element = $(element);

              $element.data("title", "") // Clear the title - there is no error associated anymore
                  .removeClass("error")
                  .tooltip("destroy");
          });

          // Create new tooltips for invalid elements
          $.each(errorList, function (index, error) {
              var $element = $(error.element);

              $element.tooltip("destroy") // Destroy any pre-existing tooltip so we can repopulate with new tooltip content
                  .data("title", error.message)
                  .addClass("error")
                  .tooltip(); // Create a new tooltip based on the error messsage we just set in the title
          });
      },

      submitHandler: function(form) {
          alert("This is a valid form!");
      }
  });