Ajax.BeginForm OnFailure invoked with Response, not AjaxContext - asp.net-mvc-3

When writing Ajax data entry forms in my ASP.NET MVC3 app, I have a standard Ajax error handler, along the lines of:
function handleAjaxError(ajaxContext) {
var response = ajaxContext.get_response();
var statusCode = response.get_statusCode();
alert("Request failed, status code " + statusCode);
}
I'm now finding that the parameter sent to handleAjaxError isn't an Ajax context but the Response object itself, for some reason.
Is this a known behavior change in MVC3, maybe? Here's the form setup, if that's relevant:
#using (Ajax.BeginForm("Create", "Attendance", null, new AjaxOptions
{ OnFailure = "handleAjaxError",
OnSuccess = "alert('success')" },
new { id = "frmCreateException" }))
{
#Html.EditorFor(m => Model)
}
The controller action returns a PartialViewResult. The HTTP Exception at the moment is a 500, because I haven't yet created the view.
Thanks!

Is this a known behavior change in MVC3, maybe?
Yes, ASP.NET MVC 3 uses unobtrusive jQuery for AJAX stuff contrary to previous version which used Microsoft*.js. So the first argument passed to the error handler is the jqXHR object.
And to get the response text and status code:
alert(ajaxContext.status);
alert(ajaxContext.responseText);

Related

Best Practice for showing Page after Post

I have a View with a Form that calls a controller action Post Method to "Complete" a Package. It then needs to refresh the page its on as that contains information that will be updated, both within the view itself and also within a partial. It does use two different Controllers in different MVC Areas.
The Post works correctly and the redirect is issued, but the page is not refreshed.
I have read that instead, I should use OnSuccess within the Ajax call that calls Complete, but I thought that was for in page calls, not ones that navigate to different pages.
View Form
#using (Ajax.BeginForm("Complete", "Packages", new { Area = "Core" },
new AjaxOptions
{
HttpMethod = "POST"
}))
{
Core(Area) Packages Controller
[HttpPost]
public ActionResult Complete(int ID)
{
// Update code
// Refresh the full page
return RedirectToAction("Summary", new { Area = "Control", id = packageBuilder.CurrentPackage.ID });
}
Control (Area) Packages Controller
[HttpGet]
public ActionResult Summary(int id)
{
// Get Model
return View("Summary", model);
}
Any pointers would be warmly welcomed.
Thanks,
Chris.
The reason that your page is not refreshed after you submit the form and the redirect is not issued in the browser, is that you are submitting the request over AJAX. This is a request issued by the browser behind the scenes.
If you want to submit the form and for the page to be refreshed, I'd recommend changing your code from Ajax.BeginForm(... to Html.BeginForm(... and then it will load the page and perform the redirect as expected.
I am not quite sure how your ajax calls are structured, but if you are using the MVC Ajax helper you can just call `location.reload(); in the OnComplete method, like so:
#using (Ajax.BeginForm(new AjaxOptions{OnComplete = "javascriptfunction"}))
{
//Data and submit button
}
<script>
function javascriptfunction(){
location.reload();
}
</script>

MVC3 Razor Ajax.ActionLink won't use POST method

I've got a page that contains multiple links. These links should do an ajax post and callback. However, the link is doing a Get instead of a Post. This causes a 404 error since I do not have an action method to handle a get at the requested URL.
If I remove the HTTPPost attribute from my Action method, the link works, but the call back fails and the Json I return is rendered in a new page.
Here is the code I'm using in my view.
<td id="action-#item.ItemID">#Ajax.ActionLink("Add", "AddToOrder", new { itemID = item.ItemID }, new AjaxOptions { HttpMethod = "POST", OnSuccess = "actionCompleted" }, new { id = "add-" + item.ItemID })</td>
This ends up adding this HTML:
<td id="action-012679"><a data-ajax="true" data-ajax-method="POST" data-ajax-success="actionCompleted" href="/mysite/neworder/AddToOrder?itemID=012679" id="add-012679">Add to Order</a></td>
My Controller has the following Action Method.
[HttpPost]
public JsonResult AddToOrder(string itemID) {
return Json(new { id = itemID, Action = "Added", "Just getting this working"});
}
My callback method that is called on Success looks like this:
<script language="javascript" type="text/javascript">
function actionCompleted(response, status, data) {
alert("We have returned");
}
</script>
If I change the [HTTPPost] attribute on my action method to [HTTPGet] I get an Json error. I can fix this by adding the JsonRequestBehavior.AllowGet to my return value, but this doesn't use the call back function defined on the page and fails.
Any help would be appreciated.
Probably you don't have jquery.unobtrusive-ajax.js script attached to page and link is gracefully degraded to regular anchor.
In order to have this working properly. You need to add references to these scripts on your page:
MicrosoftAjax.js
MicrosoftMvcAjax.js

Ajax.BeginForm with OnComplete always updates page

I have simple ajax form in MVC. In AjaxOptions there is OnComplete set to simple javascript function which does one thing - returns false.
#using (Ajax.BeginForm("Action", "Controller", new AjaxOptions { UpdateTargetId = "DivFormId", HttpMethod = "Post", OnComplete = "preventUpdate" }))
function preventUpdate(xhr) {
return false;
}
The problem is, that page is already updated. E.g. in one case controller returns partial view after postback, in other case it returns some Json object. I want it to update page when partial view is returned, and to show dialog window when json is returned. Unfortunately when json is returned, it clears the page (update it with json) even when OnComplete function returns false as MSDN says: To cancel the page update, return false from the JavaScript function.
How to prevent page update depending on received response?
Thank you!
----- UPDATE -------
So far I found following solution. When I don't specify UpdateTargetId, I can do manually with the response what I want. But it is still not documented behaviour with return false.
Use OnSuccess and get rid of UpdateTargetId. Like this:
#using (Ajax.BeginForm("Action", "Controller", new AjaxOptions { HttpMethod = "Post", OnSuccess = "foo" }))
{
...
}
and then:
function foo(result) {
if (result.SomePropertyThatExistsInYourJsonObject) {
// the server returned a JSON object => show the dialog window here
} else {
// the server returned a partial view => update the DOM:
$('#DivFormId').html(result);
}
}

Ajax form and UpdateTargetId after submitting data when ModelState is Invalid

On my view, I have 2 partial views.
1st partial view (PV1): user can type an item in a textbox and submit through an ajax form.
2nd partial view (PV2): user can see a list of items previously submitted.
The PV1 uses UpdateTargetId on a div on the PV2 because we would like to update our list with the newly added item.
Everything works well when items submitted on the PV1 are valid. It doesn't work when ModelState.IsValid == false when ajax form is submitted. It doesn't work because the UpdateTargetId is located on the PV2, and I need to update the PV1 for showing the ModelState Errors. So we encounter with duplicate of the PV1 on the PV2!
Below is another stackoverflow post on a similar problem but no solutions has been provided.
ASP.NET MVC AJAX change UpdateTargetId if ModelState is invalid
I think a Json alternative may be a solution but I'm wondering if we can adapt the standard Ajax form method to suit our need here?
Instead of using UpdateTargetId, you could try using OnComplete:
#using (Ajax.BeginForm(new AjaxOptions { OnComplete = "complete" }))
{
...
}
and inside this handler test whether there is an error in the resulting view:
function complete(result) {
var isError = $('span.field-validation-error', result.responseText).length > 0;
if (isError) {
// there was an error => we update the container of the form
$('#frmContainer').html(result.responseText);
} else {
// no error => we hide validation errors and update the result container
$('#frm .field-validation-error').hide();
$('#frm .input-validation-error').removeClass('input-validation-error');
$('#result').html(result.responseText);
}
}

Getting JSonResult from ASP's Ajax.ActionLink

How do I actually get the JSON from a controller method using Ajax.ActionLink? I tried searching the website, but the closest thing I got was ASP.NET MVC controller actions that return JSON or partial html
And the "best answer" doesn't actually tell you how to get JSON from the SomeActionMethod in the ajax.actionlink.
Personally I don't like the Ajax.* helpers. In ASP.NET MVC < 3 they pollute my HTML with javascript and in ASP.NET MVC 3 they pollute my HTML with HTML 5 data-* attributes which are totally redundant (such as the url of an anchor). Also they don't automatically parse the JSON objects in the success callbacks which is what your question is about.
I use normal Html.* helpers, like this:
#Html.ActionLink(
"click me", // linkText
"SomeAction", // action
"SomeController", // controller
null, // routeValues
new { id = "mylink" } // htmlAttributes
)
which obviously generate normal HTML:
click me
and which I unobtrusively AJAXify in separate javascript files:
$(function() {
$('#mylink').click(function() {
$.post(this.href, function(json) {
// TODO: Do something with the JSON object
// returned the your controller action
alert(json.someProperty);
});
return false;
});
});
Assuming the following controller action:
[HttpPost]
public ActionResult SomeAction()
{
return Json(new { someProperty = "Hello World" });
}
UPDATE:
As requested in the comments section here's how to do it using the Ajax.* helpers (I repeat once again, that's just an illustration of how this could be achieved and absolutely not something I recommend, see my initial answer for my recommended solution):
#Ajax.ActionLink(
"click me",
"SomeAction",
"SomeController",
new AjaxOptions {
HttpMethod = "POST",
OnSuccess = "success"
}
)
and inside the success callback:
function success(data) {
var json = $.parseJSON(data.responseText);
alert(json.someProperty);
}

Resources