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
Related
I`m trying to send a form in mvc with Ajax.beginform and execute on success function. The function is stated in the form and created in the scripts section. However, the function is not fired after the post is submitted.
The view is partial view and is inserted in Index page.
The method which the form calls in the controller is HttpPost and returns the view again which causes the index page to load again.( I suspect here is the problem)
Basically what im trying to achieve is to show a div in my index page(main) saying successfully record edited.
Also, in my bundle config I have the jquery val & the jquery.validate.unobtrusive.js loaded and in the web.config I added in appconfig
What could be wrong? Here is my code.
[HttpPost]
public async Task<ActionResult> EditPostedJob(JobPost job, string dt)
{
using (var context = new ApplicationDbContext())
{
var post = (from p in context.jobPosts where p.JobPostId == job.JobPostId select p).First();
post.AboutJob = job.AboutJob;
post.Headline = job.Headline;
post.JobAddress = job.JobAddress;
post.JobCity = job.JobCity;
post.JobPostCode = job.JobPostCode;
await context.SaveChangesAsync();
//return Json(post,JsonRequestBehavior.AllowGet);
return RedirectToAction("Index", "Manage");
}
}
in my main view I have this message
<div id="success-edited-job" class="alert alert-success">
<strong>Success!</strong> the posted job has been successfully edited.
</div>
and also I have the js which hides this when page is loaded. And then I add the partial view with the form and there is set the success-edited-job div to show when post is successful but it return again the index view and the div is hidden again.
this is my partialview form
#using (Ajax.BeginForm("EditPostedJob", FormMethod.Post, new AjaxOptions() { OnSuccess = "JobEditedSuccessfully", OnFailure = "JobEditFail",HttpMethod="POST" }))
and the js
<script type="text/javascript">
function JobEditedSuccessfully(data) {
alert("lol");
}
function JobEditFail(error) {
console.error(error);
}
</script>
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...
I'm trying to add a search form in the navbar on every page in my spring mvc web app, just like the one here on stackoverflow, and I'm having issues. Right now I have a working search functions on a couple of my pages, using the typical mvc forms. I take the inputted string and store a variable called "searchString" in an object I created called "searchForm.java". Then I try to query that inputted string in the database using spring data's findbycontaing method, and then put that result on the model, and then represent that on the view, using thymeleaf. However I think that the navbar should be done using ajax, since it's on every page and pages with other forms.
So I think I'm sending the string that was submitted to the search form in the navbar to the controller where I queried it in the repository to bring back search results, then I tried to put the search results on the model, but I get nothing, all it does is redirect me to the search page. I may not be making very much sense, but I'll show my code, and if anyone could let me know if I'm going about my problem in the right way or not, and if you guys see any errors in my code. Thanks in advance.
So here's my ajax and jquery to submit the form.
<script th:inline="javascript">
/*<![CDATA[*/
var token = $("meta[name='_csrf']").attr("content");
var header = $("meta[name='_csrf_header']").attr("content");
$(document).ajaxSend(function(e, xhr, options) {
xhr.setRequestHeader(header, token);
});
$(document).ready(function(){
$("#searchButton").on("click", function(ev) {
$.ajax({
url : "navSearch",
type : "post",
data : {
"newSearch" : $("#newSearch").val()
},
success : function(data) {
console.log(data);
},
error : function() {
console.log("There was an error");
}
});
});
});
/*]]>*/
</script>
There may be an issue here, because in the console in the chrome developer tools, before it redirects, a message pops up very quickly that says uncaught TypeError: Cannot read property 'toLowerCase' of undefined, and it's coming from jquery.min.js:5 so that could be my issue, but I have no idea how to go about fixing this, and I've searched for answers so far with no luck.
Here's my html form, I think this shouldn't be a problem, but who knows, so I'll put it up anyways. And I'm using thymeleaf for this view.
<form action = "setSearch" class="navbar-form navbar-right">
<div class="form-group">
<input type="text" class="form-control" placeholder="Search" id="newSearch"></input>
<input type="hidden" th:name="${_csrf.parameterName}" th:value="${_csrf.token}" />
</div>
<button type="submit" class="btn btn-default" id="searchButton">Search</button>
</form>
Here's my searchForm.java class, where I temporarily store the string to be queried in the database.
public class SearchForm {
private String searchString;
public String getSearchString()
{
return searchString;
}
public void setSearchString(String searchString)
{
this.searchString = searchString;
}
}
And Here's my controller, where I'm trying to handle the ajax submission and return it as search results on the setSearch.html page. What I'm thinking here is that the string "newSearch" from the form could be matched using the Spring Data query methods, and then be able to return it and add it to the model, but it's not working, it's just redirecting me to the /searchSet page with no data, because that's where the form action goes and that's what I tell it to return. So honestly I'm no sure if any data is even getting to this point.
#RequestMapping(value="setSearch/navSearch", method=RequestMethod.POST)
public #ResponseBody String navSearch (#RequestParam String newSearch, ModelMap model)
{
List<QuestionAnswerSet> questionAnswerSetByQuestion = (List<QuestionAnswerSet>) questionAnswerSetRepo.findByQuestionContaining(newSearch);
model.put("searchResult", questionAnswerSetByQuestion);
return "setSearch";
}
And here's an example of a working search method that I have in my controller that I use on a regular form, with no ajax, on the /searchSet page.
#RequestMapping(value="/setSearch", method=RequestMethod.GET)
public String searchGet(ModelMap model) {
SearchForm searchForm = new SearchForm();
model.put("searchForm", searchForm);
return "setSearch";
}
#RequestMapping(value="/setSearch", method=RequestMethod.POST)
public String searchPost(#ModelAttribute SearchForm searchForm, ModelMap model) {
List<QuestionAnswerSet> questionAnswerSetByQuestion = (List<QuestionAnswerSet>) questionAnswerSetRepo.findByQuestionContaining(searchForm.getSearchString());
model.put("searchResult", questionAnswerSetByQuestion);
return "setSearch";
}
UPDATE
I've changed my code in the form from <button type="submit" class="btn btn-default" id="searchButton">Search</button> to <button type="button" class="btn btn-default" id="searchButton">Search</button> and now I get the Uncaught TypeError: Cannot read property 'toLowerCase' of undefined from earlier and nothing happens with the page.
UPDATE
I can now submit the ajax form without a problem, I was missing meta tags in the header, so the csrf wasn't submitting correctly, so now I get this error in the chrome developer tools console XHR Loaded (navSearch - 405 Method Not Allowed - 7.265999971423298ms - 634B)
UPDATE
Now everything works on the Ajax side, I needed to adjust my url to match the url I had in the request mapping on the controller and it runs through all the code fine. However the overall search function still doesn't work, here's my updated controller.
I know my issue here is that I'm returning a string and not an object, but I'm not sure how to return the object and then redirect the url to the /setSearch page. It's running through the code and returning a string "setSearch" in the console, because I told it to at the end of the controller.
#RequestMapping(value="/setSearch/search", method=RequestMethod.POST)
public #ResponseBody String search (#RequestParam String newSearch, ModelMap model)
{
List<QuestionAnswerSet> questionAnswerSetByQuestion = (List<QuestionAnswerSet>) questionAnswerSetRepo.findByQuestionContaining(newSearch);
model.put("searchResult", questionAnswerSetByQuestion);
return "setSearch";
}
Here's my working ajax
<script th:inline="javascript">
/*<![CDATA[*/
var token = $("meta[name='_csrf']").attr("content");
var header = $("meta[name='_csrf_header']").attr("content");
$(document).ajaxSend(function(e, xhr, options) {
xhr.setRequestHeader(header, token);
});
$(document).ready(function(){
$("#searchButton").on("click", function(ev) {
$.ajax({
url : "/setSearch/search",
type : "post",
data : {
"newSearch" : $("#newSearch").val()
},
success : function(data) {
console.log(data);
},
error : function() {
console.log("There was an error");
}
});
});
});
/*]]>*/
</script>
but it's not working, it's just redirecting me to the /searchSet page
with no data, because that's where the form action goes and that's
what I tell it to return
You are right, it is because you are submitting the form and in the action you specify it to submit to setSearch, that is why the page is getting redirected to the same page. Just replace button type="submit" with button type="button" so that the form will not be submitted when searchButton is clicked.
In ASP.Net MVC 3.0 i am using a Ajax.Beginform
and hitting a JsonResult
on success of the form i am calling a jQuery Function.
but for some reason my form is redirecting to JsonAction
my View
#using (Ajax.BeginForm("ActionName", "Controller", null, new AjaxOptions
{
HttpMethod = "POST",
OnSuccess = "ShowResult"
}, new { id = "myform" }))
{
// All form Fields
<input type="submit" value="Continue" class="button standard" />
}
My controller
public JsonResult ActionName(FormCollection collection)
{
return Json(new { _status },JsonRequestBehavior.AllowGet);
}
jQuery
<script type="text/javascript">
function ShowResult(data) {
// alert("I am at ShowResult");
if (data.isRedirect) {
window.location.href = json.redirectUrl;
}
}
for some reason, when i click submit.
it runs the JSonResult and redirects the page to host/controller/actionname
I have included my
<script src="#Url.Content("jquery.unobtrusive-ajax.min.js")"></script>
in my layout.cshtml
can any one tell me what could be wrong?
I found the problem. Now i have to find the solution
on submit
I am validating my form
$("#myform").validate({
submitHandler: function (form) {
// my logic goes here....
}});
If i exclude the validation Ajax form works as expected.
But if i validate my form then ajax form is not working as expected
Thanks
when this happens its almost always because your script files aren't loaded
note from:
http://completedevelopment.blogspot.com/2011/02/unobstrusive-javascript-in-mvc-3-helps.html
Set the mentioned flag in the web.config:
Include a reference to the jQuery library ~/Scripts/jquery-1.4.4.js
Include a reference to the library that hooks this magic at ~/Scripts/jquery.unobtrusive-ajax.js
So load up fiddler http://fiddler2.com and see if the scripts are being called and loaded.
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);
}