Friday, March 4, 2011

ASP.NET MVC + jQuery: The new whole nine yards for Microsoft app(web) development

What is the easiest way to validate a model without requiring a round-trip to server? The answer folks is to use the venerable jQuery and its most compatible companion, ASP.NET MVC.

An aside, did you know that your inputs are already a model-material just by conforming to certain naming conventions for your control's name? And did you know also that the easiest way to achieve this is by using ASP.NET MVC's Html helpers and not coding the HTML manually? :-) I digress.

Sorry folks, jQuery and ASP.NET is not a match made in heaven, the server controls' id in ASP.NET are mangled to no end for it to be conveniently accessible from jQuery's simplified model-pushing (heheh I made up the term, the actual jQuery function is .serialize() ) mechanism. In short, use ASP.NET MVC, strongly recommended :-)


So here's our model:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.ComponentModel.DataAnnotations;

namespace MvcApplication3.Models
{
    public class Person
    {
        [Required(ErrorMessage="Last Name required")]
        public string Lastname { get; set; }

        [Required(ErrorMessage="First Name required")]
        public string Firstname { get; set; }

        [Required(ErrorMessage="Age Required")]
        [Range(0,120, ErrorMessage="Age must be between 0 and 120")]
        public int Age { get; set; }


        // sourced here: http://www.regular-expressions.info/email.html
        [Required(ErrorMessage="Email required")]
        [RegularExpression(@"[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?",
            ErrorMessage="Not a valid email")]
        public string Email { get; set; }
    
    }
}

And this is our view, coupled with client-side validation awesomeness (pertinent lines: 19, 20, 24, 78, 81, 89):

@model MvcApplication3.Models.Person

@{
    Layout = null;
}

<!DOCTYPE html>

<html>
<head>
    <title>Index</title>
</head>
<body>
    <script src="@Url.Content("~/Scripts/jquery-1.4.4.min.js")" type="text/javascript"></script>
    <script src="@Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript"></script>
    <script src="@Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/javascript"></script>

    @* add these two scripts *@
    <script src="@Url.Content("~/Scripts/MicrosoftAjax.js")" type="text/javascript"></script>
    <script src="@Url.Content("~/Scripts/MicrosoftMvcValidation.js")" type="text/javascript"></script>


    @* add this too *@
    @{ Html.EnableClientValidation(); }

    @using (Html.BeginForm(null, null, FormMethod.Post, new { id = "See" } ))
    {
        @Html.ValidationSummary(true)
        <fieldset>
            <legend>Person</legend>
    
            <div class="editor-label">
                @Html.LabelFor(model => model.Lastname)
            </div>
            <div class="editor-field">
                @Html.EditorFor(model => model.Lastname)
                @Html.ValidationMessageFor(model => model.Lastname)
            </div>
    
            <div class="editor-label">
                @Html.LabelFor(model => model.Firstname)
            </div>
            <div class="editor-field">
                @Html.EditorFor(model => model.Firstname)
                @Html.ValidationMessageFor(model => model.Firstname)
            </div>
    
            <div class="editor-label">
                @Html.LabelFor(model => model.Age)
            </div>
            <div class="editor-field">
                @Html.EditorFor(model => model.Age)
                @Html.ValidationMessageFor(model => model.Age)
            </div>
    
            <div class="editor-label">
                @Html.LabelFor(model => model.Email)
            </div>
            <div class="editor-field">
                @Html.EditorFor(model => model.Email)
                @Html.ValidationMessageFor(model => model.Email)
            </div>
    
            <p>
                <input type="submit" id="submitter" value="Create" />
            </p>
        </fieldset>
    }
    


    <script type="text/javascript">


        $("#submitter").click(function (event) {

            // this prevent the roundtrip to server            
            event.preventDefault();

            // this prevent ajax-sending if there's still an invalid logic on model
            if (!$("#See").validate().form()) return;

            $.ajax(
                {
                    url: '/Home/Create/',
                    type: 'POST',
                    dataType: 'json',
                    // .serialize is a free beer
                    data: $("#See").serialize(),
                    // whereas if there's no .serialize, you have to send individual inputs manually
                    // i.e.
                    // data: { Lastname : $("#Lastname").val(), Firstname : $("#Firstname").val() },

                    success: function (r) {
                        alert(r.Message);
                    }
                });

        });


        


    </script>
</body>
</html>


And this is the controller (pertinent lines: 24, 33, 41):

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using MvcApplication3.Models;

namespace MvcApplication3.Controllers
{
    public class HomeController : Controller
    {
        //
        // GET: /Home/

        public ActionResult Index()
        {
            return View();
        }


        public JsonResult Create(Person p)
        {

            if (ModelState.IsValid)
            {
                try
                {
                    // use your ORM of choice here to persist your model 

                    // return feedback to jQuery
                    return Json(new { Message = "Your name is " + p.Lastname + ", " + p.Firstname });
                }
                catch (Exception ex)
                {
                    return Json(new { Message = ex.Message });
                }
                
            }
            else
                // alert the user to tell the developer of an overlooked code
                return Json(new { Message = "Please contact the developer to enable client-side validation" });
        }

    }
}



Get the actual code here: http://code.google.com/p/sample-poc-for-jquery-aspnet-mvc-validation/downloads/list

Happy validating folks! :-)

No comments:

Post a Comment