A.13.0 HTML - BeginForm Vs Ajax - BeginForm
A.13.0 HTML - BeginForm Vs Ajax - BeginForm
BeginForm()
Html.BeginForm() will create a form on the page that submits its values to the server as a
synchronous HTTP request, refreshing the entire page in the process. Ajax.BeginForm() creates
a form that submits its values using an asynchronous ajax request. This allows a portion of the
page to be update without requiring that the entire page be refreshed.
We need to understand the difference between the behaviours of both Html and Ajax forms.
Ajax:
Html:
2. Will perform operations both Synchronously and Asynchronously (With some extra code
and care).
-----------------------------Add more
Ajax.BeginForm relies on JavaScript to get part of the page update. Client (who develop
the page) will write some JavaScript code which will get executed on completing of
asynchronous request. That JavaScript will be responsible for updating of partial content
in page.
In case of Html.BeginForm entire page get replaced with returned response.
Syntax
Html.BeginForm
Ajax.BeginForm
}
jQuery
jquery.unobtrusive-ajax
Html.BeginForm
</form>
Ajax.BeginForm
data-ajax-success="MySuccessFunction" data-ajax="true">
</form>
Recently one of reader in a MVC interview was asked to explain how to implement MVC
Asynchronous implementation.
-----------------------------------------Add more....
"BeginForm()" is an extension method that writes an opening "<form>" tag to the response.
"BeginForm()" is an extension method for both HtmlHelper and AjaxHelper classes. It returns an
MVCForm object from both HtmlHelper and AjaxHelper class instances so there is not much difference
but the AjaxHelper method submits the form asynchronously using JavaScript.
There are two types of the BeginForm() extension methods, they are:
Html.BeginForm()
Ajax.BeginForm()
This article explains the behavior of both "Html.BeginForm()" and "Ajax.BeginForm()" although these are
the same and return the same MvcForm object. To explain the post-back behavior of both methods we
create an application for product registeration. Let's see that step-by-step.
We create a model (actually a class) for Product that has various properties to store a value for the
project object. Product Model ("ProductModel.cs") is:
using System.Collections.Generic;
using System.Web.Mvc;
using System.ComponentModel.DataAnnotations;
namespace FormTypesMvcApplication.Models
{
public class ProductModel
{
public ProductModel()
{
Category = new List<SelectListItem>();
Category.Add(new SelectListItem
{
Text = "Books",
Value = "1"
});
Category.Add(new SelectListItem
{
Text = "Mobiles & Tablets",
Value = "2"
});
Category.Add(new SelectListItem
{
Text = "Laptops & Accessories",
Value = "3"
});
}
public int ProductId { get; set; }
[Required]
public string Name { get; set; }
public string Description { get; set; }
public string Manufacturer { get; set; }
[RegularExpression(@"^\$?\d+(\.(\d{2}))?$")]
public decimal BasePrice { get; set; }
public IList<SelectListItem> Category { get; set; }
public int CategoryId { get; set; }
}
}
Create a product controller where we define action methods that return a view and form submitting
data. Here we create a controller ("ProductController.cs").
Create an ActionResult return type action method that returns a view with an empty model. This action
method loads our view whenever we make a request from the browser. The action method is:
public ActionResult ProductHtml()
{
ProductModel model = new ProductModel();
return View(model);
}
We create a strongly typed view with help of Product model that uses the Html.BeginForm() method to
create a form. The BeginForm() method is an extension method of the HtmlHelper class that writes an
opening "<form>" tag and it also calls the "Dispose()" method that writes a closing "</form>" tag.
Because the MvcForm class implements the IDisposable interface, we can call the Dispose() method of
the IDisposable interface to dispose of the MvcForm class object. We create an MvcFrom as in the
following:
@{
MvcForm mvcForm = Html.BeginForm();
<div>My Html Form</div>
mvcForm.Dispose();
}
And that code renders in the opening "<form>" and closing "</form>" tags on the browser when it's
loaded. We get the source code in the browser as in the following:
<form action="/Product/ProductHtml" method="post">
<div>My Html Form</div>
</form>
Here the action and method type properties have their values. The method type is "post" so the Product
controller's "ProductHtml()" action method will be called on the form submit that handles the post
request.
We can write the same code to create both opening <form> and closing </form> tags as in the following:
@using(Html.BeginForm())
{
<div>My Html Form</div>
}
Now we create our view (ProductHtml.cshtml) to show data in the UI and the code for that is:
@model FormTypesMvcApplication.Models.ProductModel
@using System.Web.Mvc.Html;
@{
ViewBag.Title = "Product Master HTML";
}
<h2>Product Master</h2>
<fieldset>
<legend>Product</legend>
@using (Html.BeginForm())
{
<div class="formRowContainer">
<div class="labelContainer">Name</div>
<div class="valueContainer">
@Html.TextBoxFor(model => model.Name)
@Html.ValidationMessage("Name")
</div>
</div>
<div class="clearStyle"></div>
<div class="formRowContainer">
<div class="labelContainer">Description</div>
<div class="valueContainer">@Html.TextBoxFor(model => model.Description)</div>
</div>
<div class="clearStyle"></div>
<div class="formRowContainer">
<div class="labelContainer">Manufacturer</div>
<div class="valueContainer">@Html.TextBoxFor(model => model.Manufacturer)</div>
</div>
<div class="clearStyle"></div>
<div class="formRowContainer">
<div class="labelContainer">Price</div>
<div class="valueContainer">
@Html.TextBoxFor(model => model.BasePrice)
@Html.ValidationMessage("BasePrice")
</div>
</div>
<div class="clearStyle"></div>
<div class="formRowContainer">
<div class="labelContainer">Category</div>
<div class="valueContainer">
@Html.DropDownListFor(model => model.CategoryId, Model.Category, "--Select--")
</div>
</div>
<div class="clearStyle"></div>
<div class="buttonContainer">
<button>Add Product</button>
</div>
}
</fieldset>
We know that when the form is submited, the Post method executes. In the "BeginForm()" method we
did not pass any action and controller name so the default action method means that as the view name
action method is called to handle the post of the data request. So it creates an action that returns form
data into the content to be shown on the UI on form submission.
[HttpPost]
public ActionResult ProductHtml(ProductModel model)
{
if (ModelState.IsValid)
{
System.Text.StringBuilder sb = new System.Text.StringBuilder();
Create an ActionResult return type method that returns a view with empty model. This action method
loads our view whenever we make a request from a browser. The action method is as in the following:
public ActionResult ProductAjax()
{
ProductModel model = new ProductModel();
return View(model);
}
When we use "Ajax.BeginForm()" then the form will be submited using JavaScript. We are using
"_Layout.cshtml" as a shared layout so add the JavaScript file "jquery.unobtrusive-ajax.min.js" reference
on it to handle the ajax form submission request on post-back.
Now to handle the request we add "UnobtrusiveJavaScriptEnabled" as a key in the web.config file under
the "<appSettings>" section.
<appSettings>
<add key="webpages:Enabled" value="false" />
<add key="ClientValidationEnabled" value="true"/>
<add key="UnobtrusiveJavaScriptEnabled" value="true"/>
</appSettings>
Now we create a view that has an Ajax form. The Ajax.BeginForm() method has three arguments, these
are actionName, controllerName and AjaxOptions. We are using the AjaxOptions object UpdateTargetId
property that has a value of a control id where the response will be shown after the post request. In the
following code we are passing the div id so the result data will be shown in that div.
@model FormTypesMvcApplication.Models.ProductModel
@{
ViewBag.Title = "Product Master Ajax";
}
<h2>Product Master</h2>
<fieldset>
<legend>Product</legend>
@using (Ajax.BeginForm("ProductAjax", "Product", new AjaxOptions { UpdateTargetId =
"Productresult" }))
{
<div id="Productresult"></div>
<div class="formRowContainer">
<div class="labelContainer">Name</div>
<div class="valueContainer">
@Html.TextBoxFor(model => model.Name)
@Html.ValidationMessage("Name")
</div>
</div>
<div class="clearStyle"></div>
<div class="formRowContainer">
<div class="labelContainer">Description</div>
<div class="valueContainer">@Html.TextBoxFor(model => model.Description)</div>
</div>
<div class="clearStyle"></div>
<div class="formRowContainer">
<div class="labelContainer">Manufacturer</div>
<div class="valueContainer">@Html.TextBoxFor(model => model.Manufacturer)</div>
</div>
<div class="clearStyle"></div>
<div class="formRowContainer">
<div class="labelContainer">Price</div>
<div class="valueContainer">
@Html.TextBoxFor(model => model.BasePrice)
@Html.ValidationMessage("BasePrice")
</div>
</div>
<div class="clearStyle"></div>
<div class="formRowContainer">
<div class="labelContainer">Category</div>
<div class="valueContainer">
@Html.DropDownListFor(model => model.CategoryId, Model.Category, "--Select--")
</div>
</div>
<div class="clearStyle"></div>
<div class="buttonContainer">
<button>Add Product</button>
</div>
}
</fieldset>
We know that when a form is submited the Post method executes. In the "BeginForm()" method we
passed an action name and controller name so that the action method will be called that handles the
post data request. So it creates an action that returns the form data into the content to be shown on the
UI on form submission.
[HttpPost]
if (ModelState.IsValid)
{
If you've been working with ASP.NET MVC, then you are almost certainly familiar with
Html.BeginForm(). Html.BeginForm() is an HTML helper that makes it easier to write an HTML
form block in an MVC view.
Listing 1 shows how you would use this helper in a Razor view. The using statement is used to
ensure that the form is closed at the end of the using block. (This is exactly the same using
keyword that we can use in C# code to ensure objects are disposed once execution leaves the
using block.) The resulting HTML is shown in Listing 2.
Listing 1: Using Html.BeginForm() to create an HTML form
@using (Html.BeginForm())
{
<fieldset>
@Html.LabelFor(m => m.EmailAddress)
@Html.TextBoxFor(m => m.EmailAddress)
@Html.ValidationMessageFor(m => m.EmailAddress)
<input type="submit" value="Submit" />
</fieldset>
}
Note that, in the example above, the form is just posting back to the same action.
Html.BeginForm() has a number of overloads that take additional arguments for doing things
like posting to another action.
There are times when, in response to the user submitting a form, you don't want the entire
page to refresh. For example, let's say you have a small form to send an email. When the user
sends that email, you might want them to remain on the current page. Perhaps you'd like to
simply pop up a message that says the email was sent, rather than refreshing the entire page or
redirecting to another page. Depending on your application's workflow, this approach might
provider a better user experience. And AJAX is the perfect solution for implementing this type
of behavior.
You can use AJAX in combination with the HTML.BeginForm() helper. For example, you could
write jQuery to handle $('form').submit() and simply write your own code to perform an AJAX
post or any other custom tasks.
There's nothing about Html.BeginForm() that is incompatible with AJAX posts. However, if you
are looking for syntax to perform an AJAX post that is as simple and easy as the syntax
described above for performing regular posts, then you'll be interested in the Ajax.BeginForm()
HTML helper.
Ajax.BeginForm()
Listing 3 shows some code that uses Ajax.BeginForm(). The code specifies an action in the
current controller that the data will be posted to. It also specifies a JavaScript function to call
after the AJAX post succeeds, and another function to call should the AJAX post fail.
My OnSuccess() function simply displays the string returned from the action. We could also
return complex JSON objects if we needed additional information. My OnFailure() function just
displays a general error message.
I should point out that, if there is an error in my action, it's up to me to handle that error and
return an appropriate result. The OnSuccess() function will still be called. OnFailure() only gets
called if there was an error during the process of calling or returning from the action.
@using (Ajax.BeginForm("PerformAction",
new AjaxOptions { OnSuccess = "OnSuccess", OnFailure = "OnFailure" }))
{
<fieldset>
@Html.LabelFor(m => m.EmailAddress)
@Html.TextBoxFor(m => m.EmailAddress)
@Html.ValidationMessageFor(m => m.EmailAddress)
<input type="submit" value="Submit" />
</fieldset>
}
<script type="text/javascript">
function OnSuccess(response) {
alert(response);
}
function OnFailure(response) {
alert("Whoops! That didn't go so well did it?");
}
</script>
The code above also demonstrates that client-side validation still works for forms created with
Ajax.BeginForm(). Just make sure you include the appropriate JavaScript files.
Conclusion
I should point out, however, that there are some who prefer not to use this helper. Some
developers prefer using Html.BeginForm() and then writing jQuery to implement the AJAX post,
a technique I described earlier in this article. These developers sometimes feel that writing their
own jQuery gives them more control.
So it's probably a trade off between a convenience that requires less typing and an approach
that gives you maximum control. As long as you understand the two approaches, you'll be in a
good position to judge which one makes the most sense for you.