Ajax.BeginForm OnFailure invoked when ModelState is InValid - asp.net-mvc

I want to call "OnFailure" when ModelState is not valid in controller.
In My LoginView
#using (Ajax.BeginForm("Login", new AjaxOptions { HttpMethod = "POST", UpdateTargetId = "Login",InsertionMode = InsertionMode.Replace, OnSuccess = "Success", OnFailure = "onError" }))
{
}
In Controller
[httpPost]
public ViewResult Login(LoginModel model)
{
if (ModelState.IsValid)
{
}
else
{
ModelState.AddModelError("login is fail")
}
return View("Login",model)
}
so i want call onSuccess Method if ModelState is valid and if it fail then call only OnError method with display all error which are in Model State.

Here's what you could do:
[HttpPost]
public ActionResult Login(LoginModel model)
{
if (ModelState.IsValid)
{
// everything went fine and we want to redirect in this case =>
// we pass the url we want to redirect to as a JSON object:
return Json(new { redirectTo = Url.Action("SomeController", "SomeAction") });
}
else
{
// there was an error => add an error message
ModelState.AddModelError("login is fail")
}
// return a partial view instead of a full vire
return PartialView("Login",model)
}
and then all you need is the Success function:
#using (Ajax.BeginForm("Login", new AjaxOptions { HttpMethod = "POST", OnSuccess = "loginAjaxSuccess" }))
{
}
in which you could test in which case you are:
function loginAjaxSuccess(result) {
if (result.redirectTo) {
// the controller action returned a JSON result => it was a successful login
// => we redirect the browser to this url
window.location.href = result.redirectTo;
} else {
// the action returned a partial view with the form containing the errors
// => we need to update the DOM:
$('#Login').html(result);
}
}
By the way if you are using unobtrusive client side validation in the case of error where you are refreshing the form you will need to manually force the parsing of the new validation rules, otherwise next time you attempt to submit the form, client validation won't work:
} else {
// the action returned a partial view with the form containing the errors
// => we need to update the DOM
$('#Login').html(result);
// Now that the DOM is updated let's refresh the unobtrusive validation rules on the form:
$('form').removeData('validator');
$('form').removeData('unobtrusiveValidation');
$.validator.unobtrusive.parse('form');
}

When you detect the problem in the ModelState, set the StatusCode of the response object to something like 400 (You can get the code from the System.Net.HttpStatusCode class)
That will fire the onfailure method.
Si

Related

HTTPPOST Attribute not working in MVC

i have a Controller in which two actions are defined.
public class ExamlpeController : Controller
{
[Route("Index")]
public ActionResult Index()
{
return View(new ExampleViewModel { Message = new MessageDisplay { MessageVisible = false, IsGoodMessage = true, Message = String.Empty } });
}
// POST:
[HttpPost]
[Route("Index/{exampleData?}")]
public ActionResult Index(ExampleViewModel exampleData)
{
if (!ModelState.IsValid) // If model state is invalid
// Return view with validation summary
return View(new ExampleViewModel { Message = new MessageDisplay { MessageVisible = false, IsGoodMessage = true, Message = String.Empty } });
else // If model state is valid
{
// Process further
bool isGoodMessage = true; // Default
string message = "success";
isGoodMessage = true;
message = "test data";
// Clear model state if operation successfully completed
if (isGoodMessage)
ModelState.Clear();
return View(new ExampleViewModel { Message = new MessageDisplay { IsGoodMessage = isGoodMessage, MessageVisible = true, Message = message } });
}
}
}
so, when my view is called then first "Index" action is called but when i post my form it also called first index method.
this code is working fine in old build, new build contains some changes which are not related to this Controller, but it is not working,
when i add HTTPGET Attribute with first action then it is working fine,
first action called on page load and second action is called on page post.
so, my question is that how Routes are maintained the route table and what is the reason for that condition.
On your POST action change [Route("Index/{exampleData?}")] to [Route("Index")] and it should work. You don't include the POSTed view model as part of the route - think about it, how would it display that posted data in the URL anyway?

MVC5 Ajax returned Partial not being rendered

I have the following code. When I subit via Ajax, I can see the call go to the controller, and it returns the correct results. However, although it returns success, the partial is not being updated. Its almost certainly something stupid I am doing, but I have been starting at this so long now that Im going round in circles.
My suspicion is that I need to handle JSON data differently if I want to display it as a set of models in a partial. But as I am still finding my feet with MVC and ajax, its a lot of trial and error at present.
#{
System.Web.Mvc.Ajax.AjaxOptions ajaxopts = new AjaxOptions()
{
HttpMethod = "Post",
UpdateTargetId = "dlrsTable",
OnBegin = "OnBegin",
OnComplete = "OnComplete",
OnSuccess = "OnSuccess",
OnFailure = "OnFailure"
};
}
#using (Ajax.BeginForm("RefreshGrid", "Dealership", ajaxopts, new { id = "allDlrs" }))
{
#Html.Hidden("showArchived", false )
#Html.Hidden("ShowPage", 0)
#Html.AntiForgeryToken()
<div id="dlrTable">
#{Html.RenderPartial("_allDealerships", Model);}
</div>
}
and my controller;
public async Task<JsonResult> RefreshGrid(bool? showArchived, int? ShowPage)
{
try
{
//code elided, I can see it works and mappedDlrs contains the new data I want
return new JsonResult(){ Data = mappedDlrs };
}
catch (Exception ex)
{
_log.Error(ex, string.Format("Error in DealershipController.AllDealerships - Session {0}", Session.SessionID));
return new JsonResult() { Data = "Error curred" };
}
}
Your update target and div IDs do not match.
UpdateTargetId = "dlrsTable"
<div id="dlrTable">
Note the missing s in the div id (or extra one in the UpdateTargetId)

making HTTP post request with confirmation message for delete

I want to delete an item by getting confirmation from user & I want to delete it with POST method.
Here's my code snippet
#Html.ActionLink("Delete","Delete",new { id=item.UserId },new AjaxOptions {HttpMethod = "POST", Confirm = "Do you really want to delete this?"})
& my action method is:
[HttpPost]
public ActionResult Delete(int? id, LearningMVC.Models.User userDetails)
{
try
{
var dbContext = new MyDBDataContext();
var user = dbContext.Users.FirstOrDefault(userId => userId.UserId == id);
if (user != null)
{
dbContext.Users.DeleteOnSubmit(user);
dbContext.SubmitChanges();
}
return RedirectToAction("Index");
}
catch
{
return View();
}
}
If I remove the [HttpPost] attribute, It just deletes the record without any confirmation. It's giving 404 error with [HttpPost] attribute.
I have included jquery-1.5.1.min.js, unobtrusive-ajax.js, MicrosoftAjax.js, MicrosoftMvcAjax.js in the said order in layout page.
what I am missing here?
I believe that you wanted to write:
#Ajax.ActionLink("Delete", "Delete",
new { id = item.UserId },
new AjaxOptions { HttpMethod = "POST", Confirm = "Do you really want to delete this?" })
Just use AjaxHelper instead of HtmlHelper.

How to update parent view after submitting a form through a partial view?

I have a view which when a teacher is logged in lists the complete details of a student , it also lists the tasks given to the student by the teacher logged in. If the teacher wants to create a new task for the student he clicks the create new link which in turns make an Ajax call to the controller:
#Ajax.ActionLink("Create", "CreateTask", "Task", new { id = Model.StudentId },
new AjaxOptions
{
HttpMethod = "GET",
InsertionMode = InsertionMode.Replace,
UpdateTargetId = "create-div"
}, new { #class = "btn btn-default" })
which returns a partial view
[HttpGet]
public ActionResult CreateTask(int ?id)
{
//........
return PartialView("PartialViews/Task/_CreateTaskPartial");
}
In the partial view I am using Ajax.BeginForm to submit the data to create the actual task as follows
#using (Ajax.BeginForm("CreateTask", "Task",new AjaxOptions { UpdateTargetId = "create-div", InsertionMode = InsertionMode.Replace }))
{
// Form data
}
and finally in the CreateTask controller I create the task
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create([Bind(Include="TaskId")] Task #task)
{
if (ModelState.IsValid)
{
db.Tasks.Add(#task);
db.SaveChanges();
// If everything is successfull return empty
return new EmptyResult();
}
// If model errors send the view back
return PartialView("PartialViews/Task/_CreateTaskPartial", #task);
}
It creates the new task successfully but it does not update the main view which lists the details of a student and a list of created tasks. I have to refresh the page to see the last task added.
How can I make it possible so that when a 6th task is added via partial view, on success it updates the parent view and lists the 6th task also ?
I am not very experienced in MVC so please correct me where am I doing wrong.
I solved it, I got help from Here to solve it.
So what I did is instead of returning an EmptyResult() when the task is created I returned a JSON object
if (ModelState.IsValid)
{
db.Tasks.Add(#task);
db.SaveChanges();
// If everything is successfull return empty
//return new EmptyResult();
return Json(new { ok = true, url = Url.Action("Details","Student",new{id=#event.StudentId}) });
}
An d in the partial view which submits the form to vreate the task I added OnSuccess parameter in the AjaxOptions in the Ajax.BeginForm which calls a javascript function.
#using (Ajax.BeginForm("CreateTask", "Task",new AjaxOptions { UpdateTargetId = "create-div", InsertionMode = InsertionMode.Replace,OnSuccess = "onSuccess" }))
{
// Form data
}
And finally in the "onSuccess" function I cheked if the result is ok then redirect to the url in the result given by the controller.
var onSuccess = function doIt(result) {
if (result.ok) {
window.location.href = result.url;
}
};

How to return back a message after a submit

I have the following code which is not working as expected. I want to have a retrun from the controller and using alert display the value returned from the controller.
$('#change').dialog({
autoOpen: false,
width: 380,
buttons: {
"Close": function() {
$(this).dialog("close");
},
"Accept": function() {
var test = $("#ChangePasswordForm").submit();
alert(test);
}
}
});
In my controller I want to return a string
[AcceptVerbs(HttpVerbs.Post)]
public string ChangePassword(string Name)
{
var msg = "Cool!";
if (name != null)
return msg;
}
How can I do that?
Your controller needs to return a type that derives from an ActionResult.
If you want to display a simple confirmation message you can add it to the ViewData bag like this:
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult ChangePassword(string name)
{
if (!string.IsNullOrEmpty(name))
{
ViewData["msg"] = "Cool";
}
return View();
}
Then, in your view, check for the presence of the value, and display it if it's there:
<% if(ViewData["msg"] != null) { %>
<script type="text/javascript">alert('<%= ViewData["msg"].ToString() %>')</script>
<%} %>
First of all, im assuming you are using an ajax form for this. I also assume you have a or something for putting your text into. All you have to do is set the UpdateTargetId to point at the id of the element you want to update with the text
<%using (Ajax.Form("ChangePasswordForm", new AjaxOptions { UpdateTargetId = "result" })) %>
.
[HttpPost]
public ContentResult ChangePassword(string s)
{
var msg = "Cool!";
if ( s != null ? return Content(msg, "text/plain") : return Content("An error has occured", "text/plain") );
}
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult ChangePassword(string Name)
{
var msg = "Cool!";
if (name != null)
{
return Content(msg, "text/plain");
}
else
{
return Content("Error...", "text/plain");
}
}
Don't submit the form as that will perform a postback and cause the dialog to be removed.
Instead perform an AJAX post to the Controller Action and return a JsonResult containing the data.
Hook into the success callback from the Ajax request, and call alert passing the data from the Json object.
You'll probably wan't to use a loading mask after clicking submit so the user knows something is going on.

Resources