codethinked (kōdthĭngked) adj. To be consumed by or obsessed with code.

Spiff Up Your ASP.NET MVC Forms With jQuery

Since many people who are being introduced to ASP.NET MVC are being simultaneously introduced to jQuery I felt like I’d give you a quick introduction to a few jQuery plug-ins that will help you make better forms. But most importantly make your forms better without you really having to do too much to them.

What I am going to show you here is nothing new, but hopefully it will introduce a few people to the joys of jQuery plugins. The plugins that we are going to take a look at are jquery.blockUI, jquery.form, and jquery.datePicker. We are also going to introduce you to a good bit of standard jQuery.

But first, let’s start off by talking about what each of these plug-ins will do for you. The blockUI plugin will give you that cool effect that overlays the UI with a modal dialog and fades out the background. The form plugin lets you post forms via javascript. The datePicker plugin does exactly what it says, it creates date pickers. The jQuery UI project has a date picker as well, but this is just a simple usable date picker.

Our goal is to end up with a form that has watermarks:

Watermark

Row Highlighting:

Row Highlighting

Hovering help messages:

Hovering Messages

Ajax Submit with Modal Dialog:

 Modal Dialog

And a date picker:

Date Picker

First we are going to start off with a simple ASP.NET MVC form:

<div id="messages"></div>   
<% using (Html.BeginForm()){ %>        
    <fieldset>
        <legend>Personal</legend>
        <div class="formitem">
            <label for="FirstName">First Name:</label>
            <%= Html.TextBox("FirstName", Model.FirstName, new { watermark = "First", title = "Please enter your first name." }) %>                
        </div>
        <div class="formitem">
            <label for="LastName">Last Name:</label>
            <%= Html.TextBox("LastName", Model.LastName, new { watermark = "Last", title = "Please enter your last name." }) %>                
        </div>
        <div class="formitem">
            <label for="DateOfBirth">Date of Birth:</label>
            <%= Html.TextBox("DateOfBirth", Model.DateOfBirth, new { Class="date-pick", watermark = "mm/dd/yyyy" }) %>
        </div>
        <div class="formitem">
            <label for="EmailAddress">Email Address:</label>
            <%= Html.TextBox("EmailAddress", Model.EmailAddress, new { watermark = "name@example.com", title = "Please enter your e-mail address." })%>
        </div>
        <div class="formitem">
            <label for="Street">Street:</label>
            <%= Html.TextBox("Street", Model.Street, new { watermark = "Street", title = "Please enter your street address." })%>                
        </div>
        <div class="formitem">
            <label for="City">City:</label>
            <%= Html.TextBox("City", Model.City, new { watermark = "City", title = "Please enter your city." })%>                
        </div>
        <div class="formitem">
            <label for="State">State:</label>
            <%= Html.TextBox("State", Model.State, new { watermark = "State", title = "Please enter your state." })%>                
        </div>
        <div class="formitem">
            <label for="PostalCode">Postal Code:</label>
            <%= Html.TextBox("PostalCode", Model.PostalCode, new { watermark = "Postal Code", title = "Please enter your postal code." })%>                
        </div>
        <div class="submit">                
            <input type="submit" name="Submit" />                
        </div>
    </fieldset>        
<% } %>

Looks good. It is a bit non-standard, but lets not dwell. First lets look at one of the Text Boxes that we are rendering:

Html.TextBox("FirstName", Model.FirstName, new { watermark = "First", title = "Please enter your first name." })

We are passing the name, model property, and then an anonymous type that renders out html attributes. The tag above will render out an input tag like this:

<input type="text" watermark="First" value="" title="Please enter your first name." name="FirstName" id="FirstName" class="watermark" />

So yes, the watermark attribute is non-standard and won’t validate. Sadly, with the html 4 spec there just isn’t a good place to shove data like this on a tag. jQuery has a way to store a piece of data with a tag, and it is the data method. Perhaps in the future I will implement something to make assigning this to each form field easier, but for now you can deal with my non-standard tags. This non-standard tag is how we are going to apply our watermarks to our fields.

What we have here is a pretty vanilla form and now we need to add a bit of flare to it. The first thing we are going to do is include all of our javascript files:

<script src="../../Scripts/jquery-1.3.1.min.js" type="text/javascript"></script>
<script src="../../Scripts/jquery.form.js" type="text/javascript"></script>
<script src="../../Scripts/jquery.blockUI.js" type="text/javascript"></script>
<script src="../../Scripts/date.js" type="text/javascript"></script>
<script src="../../Scripts/jquery.datePicker.js" type="text/javascript"></script>
<script src="../../Scripts/spiffy.js" type="text/javascript"></script>

Here we have imported jQuery, the plugins that we are going to use, and my own little creation “spiffy.js”. This is where all of our code will go in order to make the magic on the form.

Okay, so you have seen where we are going, and what code that we are starting off with, and so what is left? You may be saying, is all of the rest accomplished entirely in jQuery? And the answer is, “yep”. So now lets look at the “spiffy.js” file and pick through it piece by piece.

jQuery “ready” Method

First we are going to use the jQuery method that you will see in any jQuery site:

$(document).ready(function() {
    //Magic goes here!
});

This allows us to put in javascript that will be executed after the page has been fully loaded. The rest of the javascript that you see here is going to go inside of the above function.

Date Picker

First we are going to look at how to apply the date pickers. In order to do this we are going to first make the first day of the week Sunday (which we tend to do here in America) and we are going to reset the date format to an American format as well.

// date pickers
Date.firstDayOfWeek = 7;
Date.format = 'mm/dd/yyyy';
$('.date-pick').datePicker().val(new Date().asString()).trigger('change');

Then we use the jQuery “$(‘’)” method in order to find the field by class name. Then we simply call the “datePicker” method on the resulting field (or fields) and set a few options. This post is going to be long enough already so I’ll let you look them up.

Watermarks and Row Highlights

Next we are going to set our watermarks and row highlights. If you don’t mind putting code on the page to create the watermarks, then there is already a watermark plugin available. We want to just pull the watermark attribute though and use that in order to create the watermarks. This is going to require a bit of custom jQuery code, but nothing inside of each page:

// watermarks and row highlights     
$("[watermark]").each(function() {
    this.value = $(this).attr("watermark");
    $(this).addClass("watermark");
})
.focus(function() {
    if (this.value === $(this).attr("watermark")) {
        this.value = "";
        $(this).removeClass("watermark");
    }
    // add row highlight
    $(this).parents(".formitem").css("background-color", "#ddd");
})
.blur(function() {
    if (this.value === "") {
        this.value = $(this).attr("watermark");
        $(this).addClass("watermark");
    }
    //remove row highlight
    $(this).parents(".formitem").css("background-color", "");
});

Okay, so it looks big at first, but let’s break it down into a few different parts. First you’ll see the “$(‘’)” method again, followed by the “focus” method and then the “blur” method. If you look at each piece separately then you’ll find it much easier to understand.

First look at the “$(‘’)” method we use to find our elements, but we use the ‘[attribute]’ syntax to look for elements that have a particular attribute. Then we call “each” in order to loop through each field that we have found. We pass a function into the method to run on each element. What it does is set the field’s text to the text of the watermark and then applied the “watermark” class to the field. The “watermark” class is what we use to give the watermark text that “grayed out” look.

Next you’ll see the “focus” method that allows us to tie a method to the “focus” event on each field. Every method in jQuery that doesn’t do any kind of filtering will pass the same set of elements on to the next method which allows us to “chain” methods together and is one of the biggest selling points of jQuery. But anyways, the function that we pass to “focus” isn’t going to get executed right away. Instead, it will get executed whenever we enter one of the fields with a “watermark” attribute.

This function is checking to see if the text in the field is equal to the text of the watermark and if so, it sets the value to an empty string so that we can enter our own text in. It also removes the “watermark” css class so that our text is not grayed out. After that you will see that we are applying a row highlight the parent of the current field that has the class “formitem”. This allows us to highlight the current row that we are editing. Here we are using jQuery to set the color of the row directly, but most likely you would do what i did in the code just before it and set a class name. I did it this way to show how easily jQuery allows you to modify css directly.

And finally we get to the “blur” event which fires when the focus leaves the field. In the function passed to this you’ll see that we are reapplying the watermark if nothing was entered and putting the “watermark” class back. We are also resetting the row color back to nothing. Again, you probably don’t want to do this because if the row had a color already, we’d be resetting it.

Resetting the Watermarks on Postback

The above code has one issue (it is possible it has others) and that is when you submit the form, the watermarks will be sent back to the server unless they are removed before postback. This will require one more little bit of jQuery.

//remove watermark when form is submitted
$("input:image, input:button, input:submit").click(function() {
    $(this.form.elements).select("[watermark]").each(function() {
        if (this.value === $(this).attr("watermark")) {
            this.value = "";
        }
    });
});

In this javascript we find all of the inputs of type image, button, and submit and add a method to the click event. The method that we attach first looks for all form elements for the clicked element and then filters it down to only elements that have “watermark” attributes and then loops over each comparing the current text to the watermark text. If they are equal then the value of the element is cleared out. It might look a bit complex, but with the chaining abilities of jQuery it all becomes so easy!

Help Messages

Next we are going to look at those fancy help messages that will pop up next to our fields when we enter them.

// tooltips                
$(":text[title]").focus(function() {
    var field = $(this);
    field.after("<p id='tooltip'>" + this.title + "</p>");
    var position = field.offset();
    $("#tooltip")
        .css("top", (position.top + 10) + "px")
        .css("left", (position.left + field.width() + 10) + "px")
        .fadeIn("slow");
})
.blur(function() {
    $("#tooltip").remove();
});

The first thing we do here is find all input elements of type “text” with a “title” attribute and attach a method to the focus event so that it fires when the field is entered. The first thing we do is get the current field using $(this) and then calling the “after” method on it in order to add an element into the page after the current field. The element inserted will be a paragraph tag with a “tooltip” id and the text of the “title” attribute. Then we position the tooltip relative to the current field. After that all we have to do is add a method to the “blur” event to remove the tooltip upon exit.

Ajax Postback With Modal Dialog

And finally…man this post is getting out of hand. But now that we are starting to get used to jQuery we can move a bit quicker through this one. Here we are creating an object using JSON notation. So you can see that we are assigning the variable “options” a set of curly braces with some crap in it! Basically it is an object with two properties, one called “beforeSubmit” and one called “success”. Each of these properties are methods that contain code to execute when these two events happen. Then we have a property called “dataType” that we are just assigning a string of ‘json’.

Now you may be wondering where all of this is coming from, and it is simply a data structure that the “form” plugin knows about and can use to configure itself. As you can see, after we create this object we then pass it into the “ajaxForm” plugin method after we find the form on the page.

var options = {
    beforeSubmit: function(formData) {
        $.blockUI();
        formData.push({ name: 'ajax_submit', value: '1' });
    },
    success: function(result) {
        $.unblockUI();
        if (result.length == 0) {
            $("#messages").empty().append("Thanks!");
        }
        else {
            var list = $("#messages").empty()
                .append($("<ul class=\"errors\">"));
            jQuery.each(result, function(index, item) {
                list.append($("<li>").append(item));
            });
        }
    },
    dataType: 'json'
};
$("form").ajaxForm(options);

So in the “beforeSubmit” method the first thing we do is call the “block” plugin that causes a modal dialog to display during postback. Then we call “formData.push” which submits the form back to the server while setting the “ajax_submit” post variable so that ASP.NET MVC can tell that this is an ajax postback.

In the “success” method we first “unblock” the ui and check the result length to see if we got anything back in our result array. If the length is 0 then we just append “Thanks!” into our “messages” div. If we do get a list of messages back then we clear the “messages” div and append an unordered list with a class of “errors”. Then we loop through item in our array of messages and append list items for each. Since we told the "form” plugin that we were expecting a “json” datatype we knew that we could just pass back a json array and it would interpret it automatically.

Just to get it working I simply added this code inside of the controller method:

[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Index(FormCollection formData)
{
    if (Request.IsAjaxRequest())
    {
        return Json(new string[] { "Test Text!", "Test Text 2!" });    
    }
    else
    {
        return View(new Person());
    }
}

So if we detect that it is an ajax postback then an “ActionResult” of type JsonResult is returned. I have the array hardcoded with two messages for test purposes, but you get the idea. The array is serialized into json by the “Json” method on the controller class.

Summary

Phew. That was a long freaking post. We saw how to add watermarks, row highlights, date pickers, hovering tooltips, and ajax submitting to our web form. The whole point here is to learn something, and I hope you did. I know that there are probably a dozen things that could be done in a better way, and if you see any of them please let me know in the comments. If you want to look at the source, you can find it below.

Click here to get the source.

$("Microsoft").append("excitement");

I don't know about you, but I can say with certainty that I am excited again about the Microsoft platform. With today's announcement that they are going to be making jQuery a core part of the Microsoft development platform I can finally say that I think they are "getting it". Or at least Scott Guthrie and DevDiv gets it. I think that the last time I felt this excited about working on the Microsoft platform was back when the first rumblings about .net were starting to make their rounds. And guess what, back then I wasn't even working with Microsoft development tools. I was working with Borland tools, and made the switch over to .net as soon as I was able to get a job working with it. Back then my goals were to work with a powerful platform which allowed me to do what I wanted to do, and most importantly, allowed me to find work.

Over the years my priorities have changed a good bit. Thankfully I am no longer as concerned about finding work on a particular platform. I have been developing on the Microsoft platform for a many years now, and I honestly haven't had too hard of a time finding gainful employment. I am very thankful for that. What has changed from many years ago is that I am no longer as enamored about what platform I am working on. I no longer care who makes my tools, I just want the best tool for the job. I don't care what OS runs my application, as long as it is fast and stable. Just as I don't care who writes my libraries, as long as they are robust and flexible.

This is why it has been hard for many Microsoft web developers over the last few years. Those of us who really cared about writing good, standard, and usable web sites were mostly left out in the cold by Microsoft. The ASP.NET framework, while powerful, abstracted away web development to the point where it was extremely hard to work with other tools that our JSP, Python, PHP, and Ruby brethren were foaming at the mouth over. We couldn't use Prototype, Scriptaculous, and worst of all jQuery. I mean honestly, we could barely use CSS. Now, to say that we "couldn't" use these tools is a bit of a misnomer, so let me say that we could use the tools as long as we smacked them around for a few hours, put a bunch of javascript into strings, did a rain dance, and then spit it all out into our pages with injected control names.

And all of this was so that we could drop a bunch of controls on an html page without knowing any html. We sacrificed standards, interoperability, and control for an abstraction that actually kept us from learning the underlying platform. I'm not pointing any fingers here, I was guilty myself. I remember when I finally started getting serious about exploring other web development frameworks and I came to realize how bad I was with HTML! Here was a technology that I dealt with on a regular basis, that I could read and understand, but I had a very hard time writing by hand. How embarrassing! But we also have to realize that this is what the ASP.NET platform set out to do. It was trying to move developers from winforms to webforms and allow them to use some of their skills that they had attained. The web was so different from desktop development that Microsoft wanted to span the gap, and they actually did a damn fine job doing it.

But then something happened. Suddenly many of these developers that had switched over to ASP.NET started becoming real web developers. They started *gasp* writing their own javascript and trying to write xhtml compliant pages. And they found that it was a royal pain in the ass. Many Microsoft developers shunned these things as fluff, saying that there was no reason to write compliant html or roll your own javascript, it was just too hard. But Microsoft saw many good developers getting fed up with the platform and moving on to things like Ruby on Rails or Django. On the CSS front Microsoft started making things much better in ASP.NET 2.0, allowing us much more control over css class names on many controls. Things were better, but the framework still spit out tons of ugly html and inline css, which was really hard to style and work with. Many web developers were left writing their own custom controls or simply spitting out strings of html into pages.

Microsoft also started up the ASP.NET AJAX project which would allow Microsoft developers to work more easily with Ajax, and even had some decent javascript libraries for html manipulation. But many developers still felt like this wasn't enough, there were other libraries out there that they liked better, and they just wanted to be able to use them with ASP.NET. Sadly, the reality was that ASP.NET just wasn't designed with these other frameworks in mind, and therefore it would likely always be hard to use them.

Microsoft found itself in an interesting situation. On one hand, they had a framework (ASP.NET) which was being heavily adopted by many enterprises and was pretty darn easy to use for your standard CRUD web applications. But they had a smaller portion of web developers who wanted to write fast, lightweight, javascript heavy, web applications and didn't want to be bogged down by the heavy ASP.NET framework (and that freakin' page lifecycle). Even though these were a smaller portion of developers, these people were also the thought leaders and Microsoft knew that if they drove them away, then the rest of the market would be only a few years behind.

So, in steps ASP.NET MVC. Microsoft knew that they had an excellent platform in .NET and they knew that the ASP.NET framework worked for a large number of developers, but they needed a framework that worked in concert with the web. ASP.NET MVC gave Microsoft developers an alternative framework on which to build real web applications. And it allowed you to do this by getting out of the way. It let you actually write your own html if you wanted to. This was a big step for Microsoft because they had to admit that ASP.NET was not a one-size fits all solution. It was an even bigger step because they released it open source under the Microsoft Public License. And they decided to release regular source drops throughout the development cycle in order to get the community involved in evolving the platform! This was not your grandfather's Microsoft!

But while they were releasing the source code for the .net framework and releasing very good OSI certified open source licenses, they were pulling a Jekyll and Hyde. They were also releasing frameworks like Unity and MS-Test. Unity, which is Microsoft's dependency injection container, and MS-Test, which is Microsoft's NUnit clone, looked to many people as a Microsoft "me too" frameworks which added very little to the development stack and were just wasted effort because they duplicated the community efforts. Many developers were puzzled why Microsoft would go through all of the effort of creating these frameworks when they could have just supported the open source tools and even included them in their development offerings. Many people, myself included, thought that we might never see the day when Microsoft would start shipping non-Microsoft open source tools as part of their development platform.

When ASP.NET MVC was released we saw a tiny glimmer of hope in Microsoft's unwavering effort to not ship open source tools in their development offerings, and that came in the form of the Unit Test Project creation form which supported NUnit, MbUnit, xUnit and any other unit testing framework that wanted to get in on it. This was a pretty big step, because they were actually supporting the integration of open source projects that compete with one of their own tools. This is basically the equivalent of them letting the Visual Studio built in unit test runner to run any unit testing framework. But this was still pretty small compared to what was coming next.

When Microsoft announced today that they were going to include jQuery as part of the Microsoft development platform, I was totally taken aback. At first I thought that they were saying that they were going to ship jQuery with ASP.NET MVC, but they weren't, they are planning on shipping it with Visual Studio in the future! They are even going to provide support for jQuery. jQuery is slated to be a core part of their future web development platform. I think that this represents a colossal shift in Microsoft's stance on open source, and I am hoping that it leads to many more open source projects being brought into the Microsoft fold in the future.

In the end I think that Microsoft still does a lot of things that makes me shake my head, but Microsoft's announcement that they are going to include jQuery with Visual Studio, along with their impending release of ASP.NET MVC and IronRuby has me more excited about the Microsoft platform than I think I have ever been. I'm glad to see that Microsoft is making huge strides in the right direction and I think that there are countless others in the community who are excited about this as well.