While working with MVC3 and Razor views recently, we came across
the need to disable the Ajax behaviour in a form when the user
pressed a certain submit button. To give you some background,
we were working on a Shopping Cart whereby the user had the
following possible actions:
- Edit an item,
- Delete an item
- Update the quantity of an item,
- Submit the cart to Checkout
- Clear the cart
- Refresh the cart.
Now, for most cases, we wanted the cart to be refreshed without
the user having to see a post back, so Ajax was the best way to
handle this, of course. Although the application is based on
the Umbraco CMS, we developed the e-Commerce side of things in MVC3
from scratch and integrated it with Umbraco using the excellent MVCBridge add-on. This
allowed us to take advantage of all MVC has to offer.
However, the solution that follows is not dependant on Umbraco or
MVCBridge at all.
Because this is a new project and has no legacy MVC code in it,
we are able to take full advantage of the new Unobtrusive Ajax
style for binding Ajax to the form. This means that under the
hood we are using jquery's ajax engine only, and not the legacy
Microsoft one. Here's the basic form:
@using (Ajax.BeginForm(new AjaxOptions
{
OnSuccess = "updateCart"
}))
{
@Html.RenderFormToken();
<section id="shoppingCart">
<h1>Items in your Shopping Cart</h1>
<table cellpadding="0" cellspacing="0">
@foreach (var item in Model.Items.Values)
{
// Render the items, including the Edit, Delete and Update submit buttons...
}
<tr>
<td colspan="3" class="totalValue">Total Value:</td>
<td class="totalValue">@Html.DisplayFor(model => model.TotalIncTax)
@Html.HiddenFor(model => model.TotalItemCount)
@Html.HiddenFor(model => model.TotalIncTax)</td>
<td class="totalValue"></td>
</tr>
</table>
<span class="submit"><input type="submit" value="Refresh Cart" name="refresh" id="refresh" />
<input type="submit" value="Clear" name="reset" id="reset" />
<input type="submit" value="Checkout" name="checkout" id="checkout" /></span>
</section>
}
Now, when a user presses any of the submit buttons, the form will
be posted back to the server, and the new page content will be
returned to the updateCart function so that we can update the
user's view without having to refresh the page.
But we want the item Edit and the Checkout buttons to re-direct
to a new page instead of submitting back to the shopping
cart. For that to happen, we need to do two things (let's
focus on the Checkout button, which we want to re-direct to the
Checkout page):
- In the ShoppingCartController we need to check which submit
button was pressed by inspecting the form elements, and do a
Resonse.Redirect() to the appropriate page if the user pressed the
Checkout button, for example; and
- Disable the Ajax behaviour when the user presses the Checkout
button.
The code to handle the second step is as follows:
// These variables are defined here as they may be referenced in other code blocks.
// The $().ready function is used to populate them.
var cartSection = null;
var eShopCartForm = null;
$(document).ready(function () {
cartSection = $("#shoppingCart");
eShopCartForm = cartSection.closest("form");
// Disable the ajax behaviour if the checkout button is pressed. We want the form
// to submit normally so that the page can be redirected.
var checkoutSubmit = cartSection.find("#checkout");
// We supply our own handler for this button to remove the form's ajax submit handler.
checkoutSubmit.live("click", function (evt) {
// Setting this attribute to false means the ajax form submit handler won't be triggered...
eShopCartForm.attr("data-ajax", "false");
});
});
If you care to dig deeper, then I recommend taking a look
through the jquery.unobtrusive-ajax.js file that is bundled with
the MVC3 projects. Basically though we are changing the
data-ajax attribute that is generated on the form element when the
user clicks the checkout button so that the ajax submit handler
doesn't trigger.
There you have it. Any questions, suggestions, remarks,
please leave a comment...