I have an Ajax form with 3 buttons for submission/cancel. The Post goes through fine and when it redirects to the next page it should go to, the correct action is called, but that new Action detects it as an Ajax request and instead of returning the full page, it tries returning a partial.
View contains:
#using (Ajax.BeginForm("postingAction", "Controller", new AjaxOptions { HttpMethod = "post" }, new { id = "myId" }))
{
#Html.AntiForgeryToken()
#Html.ValidationSummary(true)
<buttons>
...
<input type="submit" name="Cancel" value="Cancel" class="btn btn-default" />
</buttons>
...
}
Action that is called for the post:
[HttpPost]
[ValidateAntiForgeryToken]
[Authorize(Roles = "userType1, userType2")]
public ActionResult postingAction(myViewModel model)
{
if (Request.Form["Cancel"] != null)
return RedirectToAction("Action2", "DiffController");
...
}
Now when this RedirectToAction happens, this second action still detects that it was an Ajax call, how do I remove that it was an ajax call and make it a normal call?
Thanks,
David K.
Try returing JavaScriptResultwith desired url.
[HttpPost]
[ValidateAntiForgeryToken]
[Authorize(Roles = "userType1, userType2")]
public ActionResult postingAction(myViewModel model)
{
if (Request.Form["Cancel"] != null)
return JavaScript( "window.location = '" + Url.Action("Action2","DiffController") + "'" )
...
}
http://msdn.microsoft.com/en-us/library/system.web.mvc.controller.javascript%28v=vs.118%29.aspx
Related
I'm trying to get errors to show up after an ajax submit has returned an error. I'm not sure what I'm missing, but I can't get it to work. This question is basically the same thing - ModelState.AddModelError is not being displayed inside my view but I'm still not having any luck. My experience with Ajax and MVC (any version) is still a bit limited. Here is a very simple example, most of which I took from the previous link.
View: test.cshtml
#model TestProject.VisitLabResult
#Scripts.Render("~/Scripts/jquery.unobtrusive-ajax.min.js")
#Scripts.Render("~/Scripts/ckeditor/ckeditor.js")
#{
AjaxOptions ajaxOpts = new AjaxOptions
{
Url = Url.Action("test"),
HttpMethod = "Post",
LoadingElementId = "loading",
LoadingElementDuration = 500,
OnSuccess = "processData"
};
}
#Html.ValidationMessage("CustomError")
<div id="loading" class="load" style="display:none">
<p>Saving...</p>
</div>
<table>
#for (int item = 0; item < 10; item++)
{
<tr id = #item>
#using (Ajax.BeginForm(ajaxOpts))
{
#Html.ValidationSummary(true)
#Html.AntiForgeryToken()
<td>
<input type="submit" value="Create" />
</td>
<td id = #(item.ToString() + "td")>
</td>
}
</tr>
}
</table>
Controller: HomeController.cs
public ActionResult test()
{
return View();
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult test(VisitLabResult vlr, int visitid = 28)
{
try
{
if (ModelState.IsValid)
{
if (Request.IsAjaxRequest())
{
throw new Exception("error");
}
else
return View(vlr);
}
else
return View(vlr);
}
catch (Exception ex)
{
ModelState.AddModelError("CustomError", "The Same test Type might have been already created, go back to the Visit page to see the available Lab Tests");
return View(vlr);
}
}
Model
public class VisitLabResult
{
public int visitid { get; set; }
}
If it is an Ajax request I throw an error and it's caught and an error is added to ModelState. That error never shows up on the page though. Am I approaching this the right way at all? Or do I need to take a different route? I appreciate any help.
Just to clarify the solution for other people hitting this question. The ajax helper fires OnSuccess vs OnFailure based on the returned HTTP Code per the AjaxOptions docs:
OnSuccess: This function is called if the response status is in the 200 range.
OnFailure: This function is called if the response status is not in the 200 range.
In other words, you have to manually specify that there was a failure when returning your ActionResult by changing the Response.StatusCode and then returning whatever values you're expecting in your OnFailure js method. You can drive that based on any business logic you want (i.e. catch Exception ex) or !ModelState.IsValid ...)
[HttpPost]
public ActionResult Search(Person model)
{
if (ModelState.IsValid) {
// if valid, return a HTML view inserted by AJAX helper
var results = PersonRepository.Get(model)
return PartialView("Resulsts", vm);
} else {
// if invalid, return a JSON object and handle with OnFailure method
Response.StatusCode = (int)HttpStatusCode.BadRequest;
return Json(new { errors = ModelState.Values.SelectMany(v => v.Errors) });
}
}
Further Reading:
MVC 4 Ajax.BeginForm and ModelState.AddModelError
ASP.NET MVC “Ajax.BeginForm” executes OnSuccess even though model is not valid
I have a simple model called JobStatus, and I am enabling edit functionality within the Index view with an Ajax Actionlink.
My problem is that if there is a model error when editing an item, I don't know how to bring the item back to the model.
My Index action in my controller:
public ActionResult Index()
{
return View(db.JobStatuses.OrderBy(x => x.JobStatusID).ToList());
}
Here is my Index view:
#model IEnumerable<Project.Models.JobStatus>
#foreach (var item in Model)
{
<div id='#string.Format("div_{0}", item.JobStatusID)'>
#item.JobStatusID
#item.Name
#item.Description
#Ajax.ActionLink("Edit", "Edit", new { id = item.JobStatusID }, new AjaxOptions() { HttpMethod = "GET", UpdateTargetId = string.Format("div_{0}", item.JobStatusID) })
</div>
}
And here is my edit GET request:
public ActionResult Edit(string id = null)
{
JobStatus jobstatus = db.JobStatuses.Find(id);
if (jobstatus == null)
{
return HttpNotFound();
}
return PartialView(jobstatus);
}
My edit.cshtml:
#model Project.Models.JobStatus
#using Microsoft.Ajax;
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
#Html.HiddenFor(model => model.JobStatusID)
#Html.TextBoxFor(model => model.Name, null, new { #class = "form-control" })
#Html.TextBoxFor(model => model.Description, null, new { #class = "form-control" })
<input type="submit" value="Save" />
}
And finally my edit POST method:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit(JobStatus jobstatus, string action)
{
if (ModelState.IsValid)
{
db.Entry(jobstatus).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index");
}
// Not sure what to do here, how to I repopulate my index form?
return RedirectToAction("Index");
}
At the moment, on a modelstate failure the user is just redirected to the index page - what I'd like is to simply redisplay the index form, with the appropriate edit form enabled and populated, and any validation errors shown.
I've tried redirecting to my Edit action, but this just shows my form on a new page, without my index form (because currently my edit action is an ajax action)
Of course, please let me know if there is a better way to achieve this!
You can't do the RedirectToAction with Ajax Post.
Check out asp.net mvc ajax post - redirecttoaction not working
But you can load in the following way
[HttpPost]
[ValidateAntiForgeryToken]
public JsonResult Edit(JobStatus jobstatus, string action)
{
if (ModelState.IsValid)
{
db.Entry(jobstatus).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index");
}
return Json(new{id=jobStatus, success=true})
}
Once you get the JSON result from server you can load the same using the id returned
Like
$.post('/jobs/edit',{data:$(form).serialize()},function(data){
if(data.success){
$.get('/jobs/index/'+data.id,{},function(data){
$('#container').html(data);
});
}
});
I'm trying to implement a little ajax using unobtrusive ajax of mvc 3. Here is the code snippet:
Controller:
[HttpGet]
public ActionResult ViewEmployee()
{
return View();
}
[HttpPost]
public ActionResult ViewEmployee(EMPLOYEE model)
{
var obj = new EmployeeService();
var result=obj.FindEmployee(model);
return View("ViewEmployee", result);
}
View:
#{AjaxOptions AjaxOpts = new AjaxOptions { UpdateTargetId = "ajax", HttpMethod = "Post" };}
#using (Ajax.BeginForm("ViewEmployee", "Home", AjaxOpts))
{
#Html.LabelFor(x => x.EmployeeID)
#Html.TextBoxFor(x => x.EmployeeID)
<input type="submit" name="Find Name" value="Find Name" />
}
<div id="ajax">
#{
if (Model != null)
{
foreach (var x in Model.EmployeeName)
{
#x
}
}
else
{
#Html.Label("No Employee is selected!")
}
}
</div>
I debugged the code, its sending the employee id to the ViewEmployee method, finding the name but not being able to display the name back into the view.
I've activated the unobtrusive ajax property in web.config & imported the scripts into the view.
Whats going wrong with this? Please help.
This is simple but effective article, ask me if you have any more question! I resolved the problem! By the way, whats wrong with stackoverflow, i'm not getting no response literally!
http://www.c-sharpcorner.com/UploadFile/specialhost/using-unobtrusive-ajax-forms-in-Asp-Net-mvc3/
I am playing about with jQuery UI and PartialViews and have run into a problem I can't quiet get my head around.
This bit works as I expect:
<div>
#Ajax.ActionLink("Test Me!", "dialogtest", new { id = Model.Id }, new AjaxOptions { InsertionMode = InsertionMode.Replace, UpdateTargetId = "dialogtest-view" })</td>
</div>
<div id="dialogtest-view">
</div>
this GETs to this action method
[HttpGet]
public PartialViewResult DialogTest(int id)
{
//pretend to get something from DB here
var vm = new DialogUITestVM();
return PartialView("uidialog_partial", vm);
}
And returns me a PartialView which displays in the targeted div. jQuery + jQueryUI is used to pop this div up as a modal dialog. Part 1 of test done!
OK so now let's say the PartialView returned is just a basic form with a textbox, something along the lines of:
#using (Html.BeginForm("DialogTest", "pages", FormMethod.Post))
{
#Html.HiddenFor(x => x.Id)
#Html.TextBoxFor(x => x.Name)
<button type="submit">Test Me!</button>
}
This is POSTd back to the controller fine -
[HttpPost]
public ActionResult DialogTest(DialogUITestVM vm)
{
//arbitrary validation so I can test pass and fail)
if (vm.Name.Equals("Rob"))
{
//error!
vm.ErrorMessage = "There was an error you numpty. Sort it out.";
return PartialView(vm);
}
//hooray it passed - go back to index
return RedirectToAction("index");
}
However - if I make the action fail the validation, rather than targeting the PartialView to the div again, it redraws the whole page (which obviously loses the jQuery UI dialog).
What I want is: if validation fails, just update the div that contained the form.
Where am I going wrong?
You could use an Ajax form in your partial instead of a normal form and use a OnSuccess callback in your AjaxOptions:
#using (Ajax.BeginForm("DialogTest", "pages", new AjaxOptions { UpdateTargetId = "dialogtest-view", OnSuccess = "success" }))
{
#Html.HiddenFor(x => x.Id)
#Html.TextBoxFor(x => x.Name)
<button type="submit">Test Me!</button>
}
and then modify your controller action respectively:
[HttpPost]
public ActionResult DialogTest(DialogUITestVM vm)
{
//arbitrary validation so I can test pass and fail)
if (vm.Name.Equals("Rob"))
{
//error!
vm.ErrorMessage = "There was an error you numpty. Sort it out.";
return PartialView(vm);
}
//hooray it passed - go back to index
return Json(new { redirectUrl = Url.Action("Index") });
}
and of course define the corresponding success callback in your javascript files:
function success(result) {
if (result.redirectUrl) {
window.location.href = result.redirectUrl;
}
}
In Post Controller , URL is like this :
http://127.0.0.1/post/5006/some-text-for-seo-friendly
{contoller}/{id}/{seo}
public ViewResult Index(){
.....
}
I used Ajax.BeginForm in index view and mapped it to AddComment action in the same controller.
#using (Ajax.BeginForm("AddComment", "Post", new AjaxOptions()
{
HttpMethod = "GET",
InsertionMode = InsertionMode.InsertAfter,
UpdateTargetId = "comment-container"
}))
{
<textarea cols="2" rows="2" name="comment" id="comment"></textarea>
<input type="submit" value="Add Comment" />
}
and in controller
public PartialViewResult AddComment(string comment){
// how can I get 5006 {id} here
}
my question is how can I get the {id} [5006] in AddComment action.
note : the hard way is using Request.UrlReferrer and split by '/' and select form array .
You need to supply the id to the BeginForm method using this overload which takes a routeValues parameter:
#using ( Ajax.BeginForm( "AddComment", "Post",
new { id = 5006 },
new AjaxOptions
{
...
Then you should just be able to take the id as a parameter of your action method:
public PartialViewResult AddComment( int id, string comment )
{
...
MVC will call AddComment with the populated id value.