The Internet has come a long way from web pages consisting of simple HTML markup and JavaScript. Popular web applications such as Gmail and Facebook have transformed users’ expectations of websites: they are no longer satisfied with basic text but instead demand rich, interactive experiences that rival those provided by native desktop applications. As users’ demands grow, modern browsers fight to keep up and do their best to implement features and specifications—such as HTML 5 and CSS3—that make these kinds of applications possible.
Though most of this book focuses on the server-side aspects of developing web applications with the ASP.NET MVC Framework, this chapter takes a break to explore the fundamentals of creating rich web applications, showing how to use jQuery library to simplify client-side development.
Browser incompatibilities have plagued web developers for decades. The differences in functionality and lack of standards between browsers have given rise to numerous client-side libraries and frameworks that attempt to address these problems by abstracting away the differences between browsers to provide a truly standard cross-browser API.
Emerging as the overwhelming favorite of these numerous libraries is the jQuery JavaScript Library, which, following its mantra of “Write less, Do more,” greatly simplifies HTML Document Object Model (DOM) traversal, event handling, animation, and AJAX interactions. As of version 3 of the ASP.NET MVC Framework, the jQuery Library is included in the ASP.NET MVC web application project templates, making it quite easy to get up and running and leverage jQuery with minimum work.
To see how jQuery helps abstract browser inconsistencies, take a look at the following code, which tries to find out the width and the height of the browser window:
var
innerWidth
=
window
.
innerWidth
,
innerHeight
=
window
.
innerHeight
;
alert
(
"InnerWidth of the window is: "
+
innerWidth
);
alert
(
"InnerHeight of the window is: "
+
innerHeight
);
This script shows alert
dialogs
with the correct height and width in most browsers, but it will throw an
error in Internet Explorer 6-8. Why? Well, it turns out that these
versions of Internet Explorer (IE) provide the same information with document.DocumentElement.clientWidth
and
document.DocumentElement.clientHeight
properties instead.
So, in order to make this snippet of code work properly across all browsers, it must be tweaked to address IE’s inconsistency, as shown in the following listing:
var
innerWidth
,
innerHeight
;
// all browsers except IE < 9
if
(
typeof
window
.
innerWidth
!==
"undefined"
)
{
innerWidth
=
window
.
innerWidth
;
innerHeight
=
window
.
innerHeight
;
}
else
{
innerWidth
=
document
.
documentElement
.
clientWidth
,
innerHeight
=
document
.
documentElement
.
clientHeight
}
alert
(
"InnerWidth of the window is: "
+
innerWidth
);
alert
(
"InnerHeight of the window is: "
+
innerHeight
);
With these changes in place, the script now works correctly in all major browsers.
Due to noncompliance with or different interpretations of W3C standards, browsers are full of quirks like this. Older browsers are notorious for not complying with the standards, or complying only partially. And while newer specifications like HTML 5 and CSS3 are still in a draft state, modern browsers are rushing to provide draft implementation of these by using their own vendor-specific twists. Imagine factoring all of these variations into your application for almost every single DOM element that you might access—not only would your code become lengthy and unwieldy, but it would constantly need updating as browsers and standards evolve and gaps in the specification are plugged, leading to a maintenance nightmare.
A good way to isolate your application code from such inconsistencies is to use a framework or library that acts as a layer between your application and the DOM access and manipulation code. jQuery is an excellent and lightweight framework that greatly reduces this friction. jQuery’s simple APIs make accessing and manipulating the DOM easy and intuitive and reduce the amount of code you need to write, allowing you to focus on your application’s functionality rather than worrying about browser inconsistencies and writing repetitive boilerplate code.
Consider the snippet we just looked at, rewritten using jQuery:
var
innerWidth
=
$
(
window
).
width
(),
innerHeight
=
$
(
window
).
height
();
alert
(
"InnerWidth of the window is: "
+
innerWidth
);
alert
(
"InnerHeight of the window is: "
+
innerHeight
);
This code looks fairly similar to the pure JavaScript code, with the following minor changes:
You can see the benefits of using jQuery—the code is quite similar to regular JavaScript, making it easier to learn and understand, yet it’s powerful enough to abstract away all cross-browser issues. Furthermore, with all of our cross-browser headaches taken care of by jQuery, the amount of code required to achieve the same functionality is reduced to just one line per property.
Not only does jQuery make it easy to get property values, it also makes it easy to set them:
// set the width to 480 pixels
$
(
window
).
width
(
"480px"
);
// set the height to 940 pixels
$
(
window
).
height
(
"940px"
);
Notice that the same functions are used to both set and get property values, the only difference being that the setter function call takes a parameter with the new value. Using a single API in different ways to get and set values makes the jQuery syntax easy to remember as well as easier to read.
The first step in manipulating DOM elements is to get a reference to the desired element. You can do this in many ways: through its ID, its class name, or one of its attributes, or by using JavaScript logic to navigate the DOM’s tree structure and manually locate the element.
For example, the following shows how to use standard JavaScript code to search for a DOM element by its ID:
<div
id=
"myDiv"
>
Hello World!</div>
<script
type=
"text/javascript"
>
document
.
getElementById
(
"myDiv"
).
innerText
=
"Hello jQuery"
;
</script>
In this simple example, you get a reference to the <div>
element by calling the document.getElementById()
method, passing it the ID element’s ID, and then changing the inner text to
“Hello jQuery”. This code will work exactly the same way in every browser,
because document.getElementById()
is
part of the JavaScript language and is supported by all major
browsers.
Consider another scenario where you want to access an element by its class name:
<div
class=
"normal"
>
Hello World!</div>
<script
type=
"text/javascript"
>
document
.
getElementsByClassName
(
"normal"
)[
0
].
innerText
=
"Hello jQuery"
;
</script>
This seems straightforward—instead of document.getElementById()
, you use document.getElementsByClassName()
and access the
first element of the array to set the innerText
property. But wait, where did the
array come from? document.getElementsByClassName()
returns an
array containing all elements that have the same class name. Luckily, in
the example above we have only one <div>
, so we know that the first element
is the one we’re looking for.
In a real-world application, though, the page will likely contain
several elements that may or may not have IDs, and there may be more than
one element with the same class name (and some elements without any class
name at all). Elements will be nested in container elements such as
<div>
, <p>
, and <span>
, as per the page design. Since the
DOM is nothing but a hierarchal tree structure, what you end up having is
elements nested inside one another and everything nested inside the root:
document
.
Consider the following example:
<div
class=
"normal"
>
<p>
Hello World!</p>
<div>
<span>
Welcome!</span>
</div>
</div>
To access the <span>
and
change its content, you would have to grab the outermost <div>
(having class="normal"
), traverse through its child
nodes, check each node to see if it is a <span>
, and then do some manipulation on
the <span>
.
A typical JavaScript code to grab the <span>
would look like:
var
divNode
=
document
.
getElementsByClassName
(
"normal"
)[
0
];
for
(
i
=
0
;
i
<
divNode
.
childNodes
.
length
;
i
++
)
{
var
childDivs
=
divNode
.
childNodes
[
i
].
getElementsByTagName
(
"div"
);
for
(
j
=
0
;
j
<
childDivs
.
childNodes
.
length
;
j
++
)
{
var
span
=
childDivs
.
childNodes
[
j
].
getFirstChild
();
return
span
;
}
}
All this code to grab just one <span>
! Now what if you wanted to access
the <p>
tag? Can this code be
reused? Certainly not, because the <p>
element is at a different node in the
tree. You would need to write similar code to grab the <p>
element, or tweak it with conditions
to find that element. And what if there were other <span>
tags within the child <div>
? How would you get to a specific
<span>
? Answering these questions
will make this code grow bigger and bigger, as you fill it with all sorts
of conditional logic.
What if you then wanted to repeat this exercise in a different place that has a slightly different structure? Or if, in the future, the markup changes a little bit, altering the structure? You’d have to adjust all of your functions to take the new hierarchy into account. Clearly, if we continue in this manner, the code will soon become unwieldy, lengthy, and invariably error prone.
jQuery selectors help us tidy up the mess. By using predefined conventions, we can traverse the DOM in just a few lines of code. Let’s take a look now to see how these conventions reduce the amount of code needed to perform the same actions as in the previous examples.
Here’s how we can rewrite the traversing logic with jQuery selectors. Selecting an element by ID becomes:
$
(
"#myDiv"
).
text
(
"Hello jQuery!"
);
We call jQuery’s $()
function,
passing in a predefined pattern. The “#” in the pattern
signifies an ID selector, so the pattern #myDiv
is the equivalent of saying document.getElementById("myDiv")
.
Once you get a reference to the element, you can change its inner
text via jQuery’s text()
method.
This is similar to setting the innerText
property, but it’s less
verbose.
An interesting thing to note here is that almost all jQuery methods return a jQuery object, which is a wrapper around the native DOM element. This wrapping allows for “chaining” of calls—e.g., you can change the text and the color of an element in one go by saying:
$
(
".normal > span"
)
// returns a jQuery object
.
contains
(
"Welcome!"
)
// again returns a jQuery object
.
text
(
"..."
)
// returns a jQuery object again
.
css
({
color
:
"red"
});
Because each call (.text()
, .css()
) returns the same jQuery object, the
calls can be made successively. This style of chaining calls makes the
code “fluent,” which makes it easy to read, and since you do not have to
repeat the element access code, the amount of overall code that you write
is reduced.
Similar to the ID pattern, selecting by class name becomes:
$
(
".normal"
).
text
(
"Hello jQuery!"
);
The pattern for a class-based selector is ".className"
.
Note
Recall that getElementsByClassName()
returns an array—in
this case, jQuery will change the text on all elements in array! So, if
you have multiple elements with the same class name, you need to put
additional filters in place to get to the right element.
Now, let’s see how easy it is to access elements with a parent-child
relation and grab the <span>
from
our original example:
$
(
".normal > span"
).
text
(
"Welcome to jQuery!"
);
The “>” indicates the parent >
child
relation. We can even filter based on the content of the span (or any
element):
$
(
".normal > span"
).
contains
(
"Welcome!"
).
text
(
"Welcome to jQuery!"
);
The .contains()
filters
out elements that contain the specified text. So, if there
are multiple spans, and the only way to differentiate (in the absence of
ID, class name, etc.) is by checking for content, jQuery selectors make
that easy, too.
jQuery offers many more selector patterns. To learn about them, check out the jQuery documentation site.
Every DOM element on the HTML page is capable of raising events, such as “click,” “mouse move,” “change,” and many more. Events expose a powerful mechanism to add interaction to the page: you can listen for events, and perform one or more actions in response, enhancing the user experience.
For example, consider a form with many fields. By listening for
the onClick
event on the
Submit button, you can perform validation on the user’s input and show any
error messages without refreshing the page.
Let’s add a button that alerts “hello events!” when clicked. In traditional HTML/JavaScript, the code would look like:
<input
id=
"helloButton"
value=
"Click Me"
onclick=
"doSomething();"
>
<script
type=
"text/javascript"
>
function
doSomething
()
{
alert
(
"hello events!"
);
}
</script>
The onclick
event handler (or
listener) is specified in the markup: onclick="doSome
thing();"
. When this button is clicked,
this code will show the standard message box displaying the text
“hello events!”
You can also attach event handlers in a nonintrusive manner, like this:
<input
id=
"helloButton"
value=
"Click Me"
>
<script
type=
"text/javascript"
>
function
doSomething
()
{
alert
(
"hello events!"
);
}
document
.
getElementById
(
"helloButton"
).
onclick
=
doSomething
;
</script>
Notice how the markup does not specify the onclick
behavior anymore? Here, we’ve separated
presentation from behavior, attaching the behavior outside the
presentation logic. This not only results in cleaner code, but also
ensures that we can reuse the presentation logic and behaviors elsewhere
without making many changes.
This is a very simple example to show how basic event handling works. In the real world, your JavaScript functions will look much more complicated and may do more than display a simple alert to the user.
Now, let’s look at the corresponding jQuery code for specifying event handlers:
<input
id=
"helloButton"
value=
"Click Me"
>
<script
type=
"text/javascript"
>
function
doSomething
()
{
alert
(
"hello events!"
);
}
$
(
function
()
{
$
(
"#helloButton"
).
click
(
doSomething
);
});
</script>
With jQuery, you first get a reference to the button using the
$("#helloButton")
selector, and then
call .click()
to attach the event handler. .click()
is actually shorthand for .bind("click", handler)
.
$(function)
is a shortcut that
tells jQuery to attach the event handlers once the DOM is loaded in the
browser. Remember that the DOM tree is loaded in a top-to-bottom fashion,
with the browser loading each element as it encounters it in the tree
structure.
The browser triggers a window.onload
event as
soon as it is done parsing the DOM tree and loading all the scripts, style
sheets, and other resources. The $()
listens for this event and executes the function (which is actually an
event handler!) that attaches various element event handlers.
In other words, $(function(){…})
is the jQuery way of scripting:
window
.
onload
=
function
()
{
$
(
"#helloButton"
).
click
(
function
()
{
alert
(
"hello events!"
);
});
}
You can also specify the event handler inline, like this:
$
(
function
()
{
$
(
"#helloButton"
).
click
(
function
()
{
alert
(
"hello events!"
);
});
});
Interestingly, if you don’t pass a function to .click()
, it triggers a click event. This is
useful if you want to programmatically click the
button:
$
(
"#helloButton"
).
click
();
// will display "hello events!"
jQuery offers a simple and powerful mechanism to manipulate the DOM, or alter properties of the DOM itself or any element.
For example, to alter CSS properties of an element:
// will turn the color of the button's text to red
$
(
"#helloButton"
).
css
(
"color"
,
"red"
);
You’ve already seen some of this in action; remember the “height” example from earlier in the chapter?
// will return the height of the element
var
height
=
$
(
"#elem"
).
height
();
In addition to simple manipulations like these, jQuery allows you to create, replace, and remove any markup from a group of elements or the document root with ease.
The following example demonstrates adding a group of elements to an
existing <div>
:
<div
id=
"myDiv"
>
</div>
<script
type=
"text/javascript"
>
$
(
"#myDiv"
).
append
(
"<p>I was inserted <i>dynamically</i></p>"
);
</script>
This results in:
<div
id=
"myDiv"
>
<p>
I was inserted<i>
dynamically</i></p>
</div>
It is just as easy to remove any element (or a set of elements):
<div
id=
"myDiv"
>
<p>
I was inserted<i>
dynamically</i></p>
</div>
<script
type=
"text/javascript"
>
$
(
"#myDiv"
).
remove
(
"p"
);
// will remove the <p> and its children
</script>
This code results in:
<div
id=
"myDiv"
>
</div>
jQuery provides several methods to control the placement of markup, as Table 4-1 illustrates.
AJAX (Asynchronous JavaScript and XML) is a technique that enables a page to request or submit data without doing a refresh or postback.
Using asynchronous requests to access data behind the scenes (on demand) greatly enhances the user experience because the user does not have to wait for the full page to load. And since the full page doesn’t have to reload, the amount of data requested from the server can be significantly smaller, which results in even faster response times.
At the heart of AJAX is the XmlHttpRequest
object, which was originally developed by Microsoft for use in
Outlook Web Access with Exchange Server 2000. It was soon adopted by
industry heavyweights such as Mozilla, Google, and Apple and is now a W3C
standard (http://www.w3.org/TR/XMLHttpRequest/).
A typical AJAX request with XmlHttpRequest
object would look like:
// instantiate XmlHttpRequest object
var
xhr
=
new
XMLHttpRequest
();
// open a new 'GET' request to fetch google.com's home page
xhr
.
open
(
"GET"
,
"http://www.google.com/"
,
false
);
// send the request with no content (null)
xhr
.
send
(
null
);
if
(
xhr
.
status
===
200
)
{
// The 200 HTTP Status Code indicates a successful request
// will output reponse text to browser's console (Firefox, Chrome, IE 8+)
console
.
log
(
xhr
.
responseText
);
}
else
{
// something bad happened, log the error
console
.
log
(
"Error occurred: "
,
xhr
.
statusText
);
}
This example creates a synchronous request (the third
parameter in xhr.open()
), which
means that the browser will pause the
script execution until the response comes back. You typically want to
avoid these kinds of synchronous AJAX requests at all costs because the
web page will be unresponsive until the response comes back, resulting in
a very poor user experience.
Luckily, it’s quite easy to switch from a synchronous request to an
asynchronous request: simply set the
third parameter in xhr.open()
to
true
. Now, because of the asynchronous nature, the browser will not
stop; it will execute the next line (the xhr.status
check) immediately. This will most likely fail because the request
may not have completed executing.
To handle this situation, you need to specify a callback—a function that gets called as soon as the request is processed and a response is received.
Let’s look at the modified code now:
// instantiate XmlHttpRequest object
var
xhr
=
new
XMLHttpRequest
();
// open a new asynchronous 'GET' request to fetch google.com's home page
xhr
.
open
(
"GET"
,
"http://www.google.com/"
,
true
);
// attach a callback to be called as soon as the request is processed
xhr
.
onreadystatechange
=
function
(
evt
)
{
// as the request goes through different stages of processing,
// the readyState value will change
// this function will be called every time it changes,
// so readyState === 4 checks if the processing is completed
if
(
xhr
.
readyState
===
4
)
{
if
(
xhr
.
status
===
200
)
{
console
.
log
(
xhr
.
responseText
)
}
else
{
console
.
log
(
"Error occurred: "
,
xhr
.
statusText
);
}
}
};
// send the request with no content (null)
xhr
.
send
(
null
);
This code is almost identical to the synchronous version, except that it has a callback function that gets executed whenever the server sends back any information.
Note
You must attach any callbacks before issuing
xhr.send()
, or they will not be
called.
Let’s look at the equivalent jQuery code. jQuery offers an .ajax()
method and various shorthands for
accomplishing common tasks using AJAX.
Here’s the jQuery version:
$
.
ajax
(
"google.com"
)
// issue a 'GET' request to fetch google.com's home page
.
done
(
function
(
data
)
{
// success handler (status code 200)
console
.
log
(
data
);
})
.
fail
(
function
(
xhr
)
{
// error handler (status code not 200)
console
.
log
(
"Error occurred: "
,
xhr
.
statusText
);
});
The first line specifies the URL from which you want to request
data. The code then specifies the callback functions for the success and
error conditions (jQuery takes care of checking for readyState
and the status code).
Notice how we didn’t have to specify the type of request (GET
) or whether it is asynchronous or not. This
is because jQuery uses GET
by default
and $.ajax()
is asynchronous by
default.
You can override these parameters (and more) to fine-tune your request:
$
.
ajax
({
url
:
"google.com"
,
async
:
true
,
// false makes it synchronous
type
:
"GET"
,
// 'GET' or 'POST' ('GET' is the default)
done
:
function
(
data
)
{
// success handler (status code 200)
console
.
log
(
data
);
},
fail
:
function
(
xhr
)
{
// error handler (status code not 200)
console
.
log
(
"Error occurred: "
,
xhr
.
statusText
);
}
});
jQuery AJAX offers many more parameters than what’s shown here. See the jQuery documentation site for details.
Note
.done()
and .fail()
were introduced in jQuery 1.8. If
you’re using an older version of jQuery, use .success()
and .error()
, respectively.
In Chapter 3, you were introduced to server-side validation techniques. In this section, you’ll see how you can enhance the user experience by performing some of the same validations purely on the client side (without making a round-trip to the server), with the help of jQuery and the jQuery validation plug-in.
ASP.NET MVC (starting with version 3) offers unobtrusive client-side validation out of the box. Client validation comes enabled by default, but you easily enable or disable it by tweaking these two settings in your web.config file:
<configuration>
<appSettings>
<add
key=
"ClientValidationEnabled"
value=
"true"
/>
<add
key=
"UnobtrusiveJavaScriptEnabled"
value=
"true"
/>
</appSettings>
</configuration>
The good part about performing client-side validation with the
jQuery validation plug-in is that it can take advantage of the DataAnnotation
attributes defined in your model, which means that you have to do very
little to start using it.
Let’s revisit the Auction
model
from Chapter 3 to see how data annotations were used in
input validation:
public
class
Auction
{
[Required]
[StringLength(50,
ErrorMessage = "Title cannot be longer than 50 characters")]
public
string
Title
{
get
;
set
;
}
[Required]
public
string
Description
{
get
;
set
;
}
[Range(1, 10000,
ErrorMessage = "The auction's starting price must be at least 1")]
public
decimal
StartPrice
{
get
;
set
;
}
public
decimal
CurrentPrice
{
get
;
set
;
}
public
DateTime
EndTime
{
get
;
set
;
}
}
And here’s the view that renders out the validation messages:
<h2>
Create Auction</h2>
@using (Html.BeginForm()) { @Html.ValidationSummary()<p>
@Html.LabelFor(model => model.Title) @Html.EditorFor(model => model.Title) @Html.ValidationMessageFor(model => model.Title, "*")</p>
<p>
@Html.LabelFor(model => model.Description) @Html.EditorFor(model => model.Description) @Html.ValidationMessageFor(model => model.Description, "*")</p>
<p>
@Html.LabelFor(model => model.StartPrice) @Html.EditorFor(model => model.StartPrice) @Html.ValidationMessageFor(model => model.StartPrice)</p>
<p>
@Html.LabelFor(model => model.EndTime) @Html.EditorFor(model => model.EndTime) @Html.ValidationMessageFor(model => model.EndTime)</p>
<p>
<input
type=
"submit"
value=
"Create"
/>
</p>
}
The validation we’re performing is quite simple, yet with server-side validation, the page has to be submitted via a postback, inputs have to be validated on the server, and, if there are errors, the messages need to be sent back to the client and, after a full page refresh, shown to the user.
With client-side validation, the inputs are checked as soon as they are submitted, so there is no postback to the server, there’s no page refresh, and the results are shown instantly to the user!
To begin with client-side validation, go ahead and reference the jQuery validation plug-in scripts in the view:
<
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>
Note
If you use Visual Studio’s “Add View” wizard to generate Create
or Edit views, you may choose the “Reference script libraries” option
to have Visual Studio add these references automatically. Instead of
the <script>
tag references shown above,
however, Visual Studio will achieve the same thing through a reference
to the ~/bundles/jquery-val
script bundle toward
the bottom of the view. See Bundling and Minification
for more information about script bundling.
If you run the application now and inspect the Create Auction page’s source (using “View Source”), you’ll see the following markup being rendered (with unobtrusive JavaScript and client-side validation enabled):
<form
action=
"/Auctions/Create"
method=
"post"
novalidate=
"novalidate"
>
<div
class=
"validation-summary-errors"
data-valmsg-summary=
"true"
>
<ul>
<li>
The Description field is required.</li>
<li>
The Title field is required.</li>
<li>
Auction may not start in the past</li>
</ul>
</div>
<p>
<label
for=
"Title"
>
Title</label>
<input
class=
"input-validation-error"
data-val=
"true"
data-val-length=
"Title cannot be longer than 50 characters"
data-val-length-max=
"50"
data-val-required=
"The Title field is required."
id=
"Title"
name=
"Title"
type=
"text"
value=
""
>
<span
class=
"field-validation-error"
data-valmsg-for=
"Title"
data-valmsg-replace=
"false"
>
*</span>
</p>
<p>
<label
for=
"Description"
>
Description</label>
<input
class=
"input-validation-error"
data-val=
"true"
data-val-required=
"The Description field is required."
id=
"Description"
name=
"Description"
type=
"text"
value=
""
>
<span
class=
"field-validation-error"
data-valmsg-for=
"Description"
data-valmsg-replace=
"false"
>
*</span>
</p>
<p>
<label
for=
"StartPrice"
>
StartPrice</label>
<input
data-val=
"true"
data-val-number=
"The field StartPrice must be a number."
data-val-range=
"The auction's starting price must be at least 1"
data-val-range-max=
"10000"
data-val-range-min=
"1"
data-val-required=
"The StartPrice field is required."
id=
"StartPrice"
name=
"StartPrice"
type=
"text"
value=
"0"
>
<span
class=
"field-validation-valid"
data-valmsg-for=
"StartPrice"
data-valmsg-replace=
"true"
></span>
</p>
<p>
<label
for=
"EndTime"
>
EndTime</label>
<input
data-val=
"true"
data-val-date=
"The field EndTime must be a date."
id=
"EndTime"
name=
"EndTime"
type=
"text"
value=
""
>
<span
class=
"field-validation-valid"
data-valmsg-for=
"EndTime"
data-valmsg-replace=
"true"
></span>
</p>
<p>
<input
type=
"submit"
value=
"Create"
>
</p>
</form>
With unobtrusive JavaScript and client-side validation enabled,
ASP.NET MVC renders the validation criteria and corresponding messages as
data-val-
attributes. The jQuery
validation plug-in will use these attributes to figure out the validation
rules and the corresponding error messages that will be displayed if the
rules are not satisfied.
Go ahead now and try to submit the form with some invalid values. You’ll see that the “submit” did not actually submit the form; instead, you’ll see error messages next to the invalid inputs.
Behind the scenes, the jQuery validation plug-in attaches an event
handler to the form’s onsubmit
event. Upon
form submit, the jQuery validation plug-in scans through all the input
fields and checks for errors against the given criteria. When it finds an
error, it shows the corresponding error message.
Being unobtrusive in nature, the jQuery validation plug-in doesn’t
emit any code to the page, nor is anything required on your part to wire
up the client-side validation logic with the page’s events. Rather, the
code to attach to the onsubmit
event,
as well as the validation logic, is part of the jquery.validate.js and jquery.validate.unobtrusive.js files.
The good thing about being unobtrusive is that if you forget to include these two scripts, the page will still render without any errors—only, the client-side validation will not happen client side!
This section was meant to show you how easy it is to start taking advantage of client-side validation and was kept simple and minimal purposefully. The jQuery validation plug-in is quite complex and offers many more features and customizations. You’re encouraged to learn more about the plug-in at the official documentation page.
jQuery makes cross-browser development a joyful experience. ASP.NET MVC’s support of jQuery out of the box means you can quickly build a rich and highly interactive client-side user interface (UI) with very few lines of code. With client-side validation and unobtrusive JavaScript, validating user input can be done with minimal effort. All of these techniques combined can help you develop highly interactive and immersive web applications with ease.
Get Programming ASP.NET MVC 4 now with the O’Reilly learning platform.
O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.