This post covers how to use the new
unobtrusive libraries in ASP.net MVC3 to provide an improved form submission
user experience utilising AJAX. The idea is to have the whole form contents
submitted and then replaced by the server generated content, be it either
the submitted form with validation errors, or a success message.
First, you need to ensure that you reference
the required javascript - jquery.unobtrusive-ajax.js (or min.js for
production).
<script src="@Url.Content("~/Scripts/jquery.unobtrusive-ajax.js")"
type="text/javascript"></script>
Each Ajax form requires at least two views.
The first view is a wrapper around the actual form content, while second
view is a partial view that contains the form itself. To demonstrate what I
mean, I have created a simple registration form (note how it used the new
IValidatableObject interface for complex model validation at binding):
The outer form is just a container that holds
the dynamic content, be it the data entry form or the success message. I've
included the current date time to demonstrate how the outer wrapper does not
change when the inner form content is submitted.
@{
ViewBag.Title = "MyForm";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h2>Register
Online - @DateTime.Now.ToString()</h2>
<div
id="formContent">
@{Html.RenderPartial("FormContent");}
</div>
As you can see, it
merely renders the content of the partial view inside an element that
becomes the target of our ajax post result. The form content, for the
purpose of this blog, is trivial. Note how I have used the Post option in
the AjaxOptions โ this is because I want data submitted to the Index()
overload of the controller that accepts HttpPost.
@model
Registration.Models.RegistrationFormModel
@{
AjaxOptions options = new AjaxOptions{
HttpMethod = "Post",
UpdateTargetId = "formContent"
};
}
@using (Ajax.BeginForm(options))
{
<fieldset>
<legend>Registration
Form</legend>
@Html.ValidationSummary(true)
<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.Surname)
</div>
<div
class="editor-field">
@Html.EditorFor(model => model.Surname)
@Html.ValidationMessageFor(model => model.Surname)
</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>
<input
type="submit"
value="Register"
/>
</div>
</fieldset>
}
I have added an
additional partial view which will be rendered when the form is successfully
submitted:
@model Registration.Models.RegistrationFormModel
<h3>You have successfully registered.</h3>
<p>Your regsitration number is @Model.RegsitrationUniqueId</p>
The controller for this form for the purposes
of this demo is pretty simple. If the model is valid then a registration is
calculated but whatever means and the Success view is returned. If the model
is invalid (becuiase the IValidatableObject interface has returned a model
error, then the data-entry form is returned back to the user to fix their
errors.
public
class
FormController : Controller
{
public ActionResult Index()
{
return View(new
RegistrationForm());
}
[HttpPost]
public PartialViewResult
Index(RegistrationForm model)
{
if (ModelState.IsValid)
{
//go and do registration business
logic,
RNGCryptoServiceProvider csp =
new RNGCryptoServiceProvider();
byte[] regsitrationBytes =
new byte[16];
csp.GetBytes(regsitrationBytes);
model.RegsitrationUniqueId = Convert.ToBase64String(regsitrationBytes);
return PartialView("Success",
model);
}
else
{
//return the data entry form
return PartialView("FormContent",
model);
}
}
}
The project layout is as follows:
When the user navigates to the registration
page:
When the user attempt to register a user who
is too young, server side validation kicks in and the data entry form is
returned:
When the data is correctly entered, the
success message is displayed:
Note how in all the images the date/time that
the registration startd has not changed โ there has been no full post back
to the server.
Of interest is how the unobtrusive ajax is
rendered to the client โ without masses of javascript but rather HTML5 valid
element attributes on the form element as follows:
<form
action="/PVA/Form/" data-ajax="true" data-ajax-method="Post" data-ajax-mode="replace"
data-ajax-update="#formContent" id="form0" method="post">
...
</form>
Conclusion
This post has demonstrated how easy it is to
provide a superior user experience using Ajax forms and the unobstrusive
javascript libraries in ASP.Net MVC 3. You can visit more interesting topic
about ASP.NET MVC 3 at
here.