MiniProfiler Throwing Unexpected Token with Ajax.BeginForm - ajax

I'm using MiniProfiler on an MVC 4 app. We have a view being rendered in a modal (using the Colorbox jquery plugin). That view then has a partial view in it with an ajax form that looks like this:
#using(Ajax.BeginForm("<action name>", "<controller name>", new {area="<area name>"}, new AjaxOptions
{
UpdateTargetId = "modal-body",
InsertionMode = InsertionMode.Replace,
HttpMethod = "POST"
}))
{
<html for form here>
}
When we submit the form it returns the same partial view to overwrite this whole section on the view. When it's posted MiniProfiler throws an error: SyntaxError: Unexpected token ,
This happens in this function:
var jQueryAjaxComplete = function (e, xhr, settings) {
if (xhr) {
// should be an array of strings, e.g. ["008c4813-9bd7-443d-9376-9441ec4d6a8c","16ff377b-8b9c-4c20-a7b5-97cd9fa7eea7"]
var stringIds = xhr.getResponseHeader('X-MiniProfiler-Ids');
if (stringIds) {
var ids = typeof JSON != 'undefined' ? JSON.parse(stringIds) : eval(stringIds);
fetchResults(ids);
}
}
};
It's expecting to a json array of guids, but instead it's getting the array twice, like this:
"["6de0e02c-e694-4d8a-ac22-ea6a847efe0e","970f6640-fe5b-45d9-bf59-c916b665458d"], ["6de0e02c-e694-4d8a-ac22-ea6a847efe0e","970f6640-fe5b-45d9-bf59-c916b665458d"]"
This causes it to puke when it tries to parse the array. I'm not sure why the array is getting duplicated. Any help would be greatly appreciated. Thanks!

This a miniprofiler bug https://github.com/MiniProfiler/ui/pull/5
Wait for next update.

Related

Redirect to partial view on another controller

I am new in asp.net mvc programming, please be gentle... :)
Please notice that the following views are all PARTIAL views! Methods are called through Ajax and redirect to partial views with lists, forms are posted through Ajax, etc. OK, here we go...
1st controller named AlertsController. One of the methods is ResolveAlert(Guid id) which returns RedirectToAction -> UnresolvedAlerts() which is just a list of unresolved alerts.
2nd contoller named FrontDeskController. One of the methods is CustomerDetails(Guid id) which lists the customer and alerts that he might have.
I want to be able to "Resolve an alert" (thus use the method of the 1st controller) but return to the page that I was before instead of going to the redirected page that the method returns.
I added a second parameter to the ResolveAlert() method which lists a returnUrl string. I manage to send the Url that I want it to redirect to but I get just the partial (not rendered inside the whole page as it should)...
Here's my ResolveAlert method on my AlertsController:
// Resolve Alert POST
[HttpPost]
public async Task<ActionResult> Resolve(AlertModel model, string redirectUrl)
{
await _AlertsService.ResolveAsync(model);
if (!string.IsNullOrWhiteSpace(redirectUrl))
return Redirect(redirectUrl);
return RedirectToAction("Unresolved");
}
...and here is my CustomerDetails() method on my FrontDeskController:
// Display Customer Alerts
public async Task<PartialViewResult> CustomerDetails(AttendanceModel model, Guid id)
{
var customer = await _CustomersService.ReadAsync(id);
ViewData["Customer"] = await _CustomersService.ReadCustomerExtendedAsync(id);
var alerts = await _AlertsService.ReadCustomerAlertsAsync(id);
ViewData["Alerts"] = alerts.Where(x => x.IsResolved == false).ToList();
return PartialView("_CustomerDetails", model);
}
The ResolveAlert() method of the first controller is called in two steps... 1st I call a modal from the CustomerDetails view:
function resolveAlert(alertId, customerId) {
var returnTo = '/FrontDesk/CustomerDetails/' + customerId;
$.ajax({
method: 'GET',
url: '/Alerts/Resolve/' + alertId,
data: {returnUrl : returnTo},
dataType: 'html'
}).then(function (html) {
$('#dialog-container').html(html);
showDialog();
});
}
...then on the modal I have:
#{
var data = Request.Params["returnUrl"];
}
#using (Ajax.BeginForm("Resolve", "Alerts", new { redirectUrl = data}, new AjaxOptions() { HttpMethod = "POST", InsertionMode = InsertionMode.Replace, UpdateTargetId = "partial", OnSuccess = "hideDialog" }, new { id = "form", #class = "form-horizontal" }))
{ ..... textbox with some notes that I can post while resolving the alert ..... }
... and (finally) here is the final part at the bottom of my modal:
<script type="text/javascript">
$('#form').validate({
rules: {
AlertNotes: {
required: true
}
},
submitHandler: function (form) {
$.ajax({
url: $(form).attr("action"),
data: $(form).serialize(),
type: $(form).attr("method")
}).then(function (result) {
$("#partial").html(result);
hideDialog();
});
}
});
</script>
I think that in order for the returned partial to get rendered correctly inside its container I should be returning a RedirectToAction from the ResolveAlert() method but the problem is that it belongs on a different controller...
Is it possible to get this working somehow or should I just bite the bullet and forget about having those pages as partials, get rid of the Ajax calls and use normal Url.Action() links?
It was just a Javascript/Ajax bug in my code.... Please disregard the question...
For those wondering, I had 2 forms using the same id. JS died silently allowing the form to be posted normally and not through Ajax. It had me scratching my head for a while now. Too bad that web development tools and VS in particular can't snipe such errors and provide a meaningful hint to assist you in debugging...

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);
}
}

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);
}

ASP.NET MVC 2: prevent ajax action link from replacing the updateTarget

I use an ajax action link on a view, then bind a js function onto its onCompleted property.
In this function, i get the response object, do some funny stuff, then write the message property to the updatetarget element.
The problem is, when it finishes its work on the oncompleted event, it writes the raw json response onto the updatetarget element, replacing the text i already written. I want to prevent it to write the raw response to the updatetarget. I'm aware of the InsertionMode property, but its useless to me because it appends text to the element one way or another.
The scripts i mentioned are below;
The code of the action link on view:
<%: Ajax.ActionLink("Delete", "Delete",
new { id = Model.Id, secretKey = Model.SecretKey },
new AjaxOptions { OnComplete = "WriteJsonResultToElement", UpdateTargetId="commandResult" })
%>
The WriteJsonResultToElement function
function WriteJsonResultToElement(resultObject) {
updateTarget = resultObject.get_updateTarget();
obj = resultObject.get_object();
$(updateTarget).text(obj.message); // here i set the text of update target
if (obj.result > 0)
$('*:contains("' + obj.id + '")').last().parent().remove();
}
My JsonResult Delete method returns this data after action:
{"message":"Deleted","result":1,"id":132}
Thanks.
If you don't want the raw JSON response appended to the DOM don't specify an UpdateTargetId:
<%: Ajax.ActionLink(
"Delete",
"Delete",
new { id = Model.Id, secretKey = Model.SecretKey },
new AjaxOptions { OnComplete = "success" })
%>
and handle it in the success callback:
function success(result) {
var obj = result.get_object();
alert(obj.message);
// TODO: do something with the object
}

Resources