HTML5-MVC application using VS2010 SP1

Posted by nmarun on ASP.net Weblogs See other posts from ASP.net Weblogs or by nmarun
Published on Wed, 09 Mar 2011 16:39:54 GMT Indexed on 2011/03/10 0:10 UTC
Read the original article Hit count: 445

This is my first attempt at creating HTML5 pages. VS 2010 allows working with HTML5 now (you just need to make a small change after installing SP1). So my Razor view is now a HTML5 page.

I call this application - 5Commerce – (an over-simplified) HTML5 ECommerce site. So here’s the flow of the application:

  • home page renders
  • user enters first and last name, chooses a product and the quantity
  • can enter additional instructions for the order
  • place the order
  • user is then taken to another page showing the order details

Off to the details. This is what my page looks in Google Chrome 10 beta (or later) soon after it renders.

image

Here are some of the things to observe on this.

  • Look a little closer and you’ll see a border around the first name textbox – this is ‘autofocus’ in action. I’ve set the autofocus attribute on this textbox. So as soon as the page loads, this control gets focus.
       1: <input type="text" autofocus id="firstName" class="inputWidth" data_minlength=""
       2:                 data_maxlength="" placeholder="first name" />
  • See a partially grayed out ‘last name’ text in the second textbox. This is set using a placeholder attribute (see above). It gets wiped out on-focus and improves the UI visuals in general.
  • The quantity textbox is actually a numerical-only textbox.
       1: <input type="number" id="quantity" data_mincount="" class="inputWidth" />
  • The last line is for additional instructions. This looks like a label but it’s content is editable. Just adding the ‘contenteditable’ attribute to the span allow the user to edit the text inside.
       1: <span contenteditable id="additionalInstructions" data_texttype="" class="editableContent">select text and edit </span>

All of the above is just plain HTML (no lurking javascript acting in here). Makes it real clean and simple. Going more into the HTML, I see that the _Layout.cshtml already is using some HTML5 content. I created my project before installing SP1, so that was the reason for my surprise.

   1: <!DOCTYPE html>

This is the doctype declaration in HTML5 and this is supported even by IE6 (just take my word on IE6 now, don’t go install it to test it, especially when MS is doing an IE6 countdown). That’s just amazing and extremely easy to read remember and talk about a few less bytes on every call! I modified the rest of my _Layout.cshtml to the below:

   1: <!DOCTYPE html>
   2: <html>
   3: <head>
   4:     <title>5Commerce - HTML 5 Ecommerce site</title>
   5:     <link href="@Url.Content("~/Content/Site.css")" rel="stylesheet" type="text/css" />
   6:     <script src="@Url.Content("~/Scripts/jquery-1.4.4.min.js")" type="text/javascript"></script>
   7:     <script src="@Url.Content("~/Scripts/CustomScripts.js")" type="text/javascript"></script>
   8:     <script type="text/javascript">
   9:         $(document).ready(function () {
  10:             WireupEvents();
  11:         });
  12:
</script>
  13:  
  14: </head>
  15:  
  16: <body role="document" class="bodybackground">
  17:     <header role="heading">
  18:         <h2>5Commerce - HTML 5 Ecommerce site!</h2>
  19:     </header>
  20:     <section id="mainForm">
  21:         @RenderBody()
  22:     </section>
  23:     <footer id="page_footer" role="siteBaseInfo">
  24:         <p>&copy; 2011 5Commerce Inc!</p>
  25:     </footer>
  26: </body>
  27: </html>

I’m sure you’re seeing some of the new tags here. To give a brief intro about them:

<header>, <footer>: Marks the header/footer region of a page or section.

<section>: A logical grouping of content

role attribute: Identifies the responsibility of an element. This attribute can be used by screen readers and can also be filtered through jQuery.

SP1 also allows for some intellisense in HTML5.

image

You see the other types of input fields – email, date, datetime, month, url and there are others as well.

So once my page loads, i.e., ‘on document ready’, I’m wiring up the events following the principles of unobtrusive javascript. In the snippet below, I’m controlling the behavior of the input controls for specific events.

   1: $("#productList").bind('change blur', function () {
   2:     IsSelectedProductValid();
   3: });
   4:  
   5: $("#quantity").bind('blur', function () {
   6:     IsQuantityValid();
   7: });
   8:  
   9: $("#placeOrderButton").click(
  10:     function () {
  11:         if (IsPageValid()) {
  12:             LoadProducts();
  13:         }
  14:     });

This enables some client-side validation to occur before the data is sent to the server.

image

These validation constraints are obtained through a JSON call to the WCF service and are set to the ‘data_’ attributes of the input controls. Have a look at the ‘GetValidators()’ function below:

   1: function GetValidators() {
   2:     // the post to your webservice or page
   3:     $.ajax({
   4:         type: "GET", //GET or POST or PUT or DELETE verb
   5:         url: "http://localhost:14805/OrderService.svc/GetValidators", // Location of the service
   6:         data: "{}",  //Data sent to server
   7:         contentType: "application/json; charset=utf-8", // content type sent to server
   8:         dataType: "json", //Expected data format from server
   9:         processdata: true, //True or False
  10:         success: function (result) {//On Successfull service call
  11:             if (result.length > 0) {
  12:                 for (i = 0; i < result.length; i++) {
  13:                     if (result[i].PropertyName == "FirstName") {
  14:                         if (result[i].MinLength > 0) {
  15:                             $("#firstName").attr("data_minLength", result[i].MinLength);
  16:                         }
  17:                         if (result[i].MaxLength > 0) {
  18:                             $("#firstName").attr("data_maxLength", result[i].MaxLength);
  19:                         }
  20:                     }
  21:                     else if (result[i].PropertyName == "LastName") {
  22:                         if (result[i].MinLength > 0) {
  23:                             $("#lastName").attr("data_minLength", result[i].MinLength);
  24:                         }
  25:                         if (result[i].MaxLength > 0) {
  26:                             $("#lastName").attr("data_maxLength", result[i].MaxLength);
  27:                         }
  28:                     }
  29:                     else if (result[i].PropertyName == "Quantity") {
  30:                         if (result[i].MinCount > 0) {
  31:                             $("#quantity").attr("data_minCount", result[i].MinCount);
  32:                         }
  33:                     }
  34:                     else if (result[i].PropertyName == "AdditionalInstructions") {
  35:                         if (result[i].TextType.length > 0) {
  36:                             $("#additionalInstructions").attr("data_textType", result[i].TextType);
  37:                         }
  38:                     }
  39:                 }
  40:             }
  41:         },
  42:         error: function (result) {// When Service call fails
  43:             alert('Service call failed: ' + result.status + ' ' + result.statusText);
  44:         }
  45:     });
  46:  
  47:     //....
  48: }

Just before the GetValidators() function runs and sets the validation constraints, this is what the html looks like (seen through the Dev tools of Chrome):

image

After the function executes, you see the values in the ‘data_’  attributes.

image

As and when we enter valid data into these fields, the error messages disappear, since the validation is bound to the blur event of the control.

image

There you see… no error messages (well, the catch here is that once you enter THAT name, all errors disappear automatically). Clicking on ‘Place Order!’ runs the SaveOrder function. You can see the JSON for the order object that is getting constructed and passed to the WCF Service.

   1: function SaveOrder() {
   2:     var addlInstructionsDefaultText = "select text and edit";
   3:     var addlInstructions = $("span:first").text();
   4:     if(addlInstructions == addlInstructionsDefaultText)
   5:     {
   6:         addlInstructions = '';
   7:     }
   8:     var orderJson = {
   9:         AdditionalInstructions: addlInstructions,
  10:         Customer: {
  11:             FirstName: $("#firstName").val(),
  12:             LastName: $("#lastName").val()
  13:         },
  14:         OrderedProduct: {
  15:             Id: $("#productList").val(),
  16:             Quantity: $("#quantity").val()
  17:         }
  18:     };
  19:  
  20:     // the post to your webservice or page
  21:     $.ajax({
  22:         type: "POST", //GET or POST or PUT or DELETE verb
  23:         url: "http://localhost:14805/OrderService.svc/SaveOrder", // Location of the service
  24:         data: JSON.stringify(orderJson), //Data sent to server
  25:         contentType: "application/json; charset=utf-8", // content type sent to server
  26:         dataType: "json", //Expected data format from server
  27:         processdata: false, //True or False
  28:         success: function (result) {//On Successfull service call
  29:             window.location.href = "http://localhost:14805/home/ShowOrderDetail/" + result;
  30:         },
  31:         error: function (request, error) {// When Service call fails
  32:             alert('Service call failed: ' + request.status + ' ' + request.statusText);
  33:         }
  34:     });
  35: }

The service saves this order into an XML file and returns the order id (a guid). On success, I redirect to the ShowOrderDetail action method passing the guid. This page will show all the details of the order.

image

Although the back-end weightlifting is done by WCF, I did not show any of that plumbing-work as I wanted to concentrate more on the HTML5 and its associates. However, you can see it all in the source here.

I do have one issue with HTML5 and this is an existing issue with HTML4 as well. If you see the snippet above where I’ve declared a textbox for first name, you’ll see the autofocus attribute just dangling by itself. It doesn’t follow the xml syntax of ‘key="value"’ allowing users to continue writing badly-formatted html even in the new version. You’ll see the same issue with the ‘contenteditable’ attribute as well.

The work-around is that you can do ‘autofocus=”true”’ and it’ll work fine plus make it well-formatted. But unless the standards enforce this, there will be people (me included) who’ll get by, by just typing the bare minimum! Hoping this will get fixed in the coming version-updates.

Source code here.

Verdict: I think it’s time for us to embrace the new HTML5. Thank you HTML4 and Welcome HTML5.

© ASP.net Weblogs or respective owner

Related posts about c#

Related posts about ASP.NET MVC