How handle different results in an ajax call? - asp.net-mvc

Suppose you have the following controller action
[HttpPost]
public ActionResult Save( CustomerModel model )
{
if (!ModelState.IsValid) {
//Invalid - redisplay form with errors
return PartialView("Customer", model);
}
try {
//
// ...code to save the customer here...
//
return PartialView( "ActionCompleted" );
}
catch ( Exception ex ) {
ActionErrorModel aem = new ActionErrorModel() {
Message = ex.Message
};
return PartialView( "ActionError", aem );
}
}
And suppose you call this action using jQuery:
$.ajax({
type: "post",
dataType: "html",
url: "/Customer/Save",
sync: true,
data: $("#customerForm").serialize(),
success: function(response) {
/*
??????
*/
},
error: function(response) {
}
});
I would like to be able to distinguish between the results I am getting to handle them in different ways on the client. In other words how can I understand that the action
returned the same model because has not passed validation
returned one of the views that represents error info/messages
Any suggestion?

One way to handle this is to append a custom HTTP header to indicate in which case we are falling:
[HttpPost]
public ActionResult Save( CustomerModel model )
{
if (!ModelState.IsValid) {
//Invalid - redisplay form with errors
Response.AppendHeader("MyStatus", "case 1");
return PartialView("Customer", model);
}
try {
//
// ...code to save the customer here...
//
Response.AppendHeader("MyStatus", "case 2");
return PartialView( "ActionCompleted" );
}
catch ( Exception ex ) {
ActionErrorModel aem = new ActionErrorModel() {
Message = ex.Message
};
Response.AppendHeader("MyStatus", "case 3");
return PartialView( "ActionError", aem );
}
}
And on the client side test this header:
success: function (response, status, xml) {
var myStatus = xml.getResponseHeader('MyStatus');
// Now test the value of MyStatus to determine in which case we are
}
The benefit of this is that the custom HTTP header will always be set in the response no matter what content type you've returned. It will also work with JSON, XML, ...
Remark 1: To avoid cluttering you controller action with all those Response.AppendHeader instructions you could write a custom ActionResult allowing you to directly specify the value of this header so that you simply return this.MyPartialView("Customer", model, "case 1")
Remark 2: Remove this sync: true attribute from the request because it makes my eyes hurt (in fact I think you meant async: 'false').

You could check for an element unique to that view, for example:
$.ajax({
type: "post",
dataType: "html",
url: "/Customer/Save",
sync: true,
data: $("#customerForm").serialize(),
success: function(response) {
var resp = $(response);
if($(resp.find("#customer").length) {
//customer returned
} else if($(resp.find("#completed").length) {
//completed view
} else if($(resp.find("#error").length) {
//error view
}
},
error: function(response) {
}
});

Related

ASP.NET MVC form on a Partial View

I have page witha table and a button. When I push the button a partial view loads into a div. On the partial view there is an ajax form which sends back the partial view with validation error in case of wrong form data but I want to remove the partial view and refresh the table in case of successful insertion.
The form header:
#using (Ajax.BeginForm("RequestInsert", "Home", new AjaxOptions { HttpMethod = "POST", UpdateTargetId = "requestForm" }, new { id = "reqins" }))
The jQuery submit event handler on the host page:
$(document).on('submit', '#reqins', function (e) {
e.preventDefault();
let data = $("form :input").serializeArray();
$.ajax({
url: '#Url.Action("RequestInsert", "Home")'
,type: "POST"
,data: { "__RequestVerificationToken": token, "model": data }
})
.done(function (data) {
$("#requestForm").html("");
table.search('').columns().search('').draw();
})
.fail(function (jqXHR, textStatus) {
alert("fail");
});
});
I am a little confused with the partial view and ajax form.
Since your objective is checking validation status from AJAX response, you can use if condition against AJAX response as shown below:
$('#reqins').submit(function (e) {
e.preventDefault();
let data = $('form :input').serializeArray();
$.ajax({
url: '#Url.Action("RequestInsert", "Home")',
type: 'POST',
data: { "__RequestVerificationToken": token, "model": data },
success: function (result) {
// check valid response
if (result.invalid) {
$('#requestForm').html(result.form);
}
else {
$('#requestForm').html(result);
table.search('').columns().search('').draw();
}
},
error: function (jqXHR, textStatus) {
alert("fail");
}
});
});
Then inside controller action you can return both validation status and partial view using Controller.Json() with RenderViewToString() extension method provided here:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult RequestInsert(ViewModel model)
{
// perform validation here
// assume IsValid is a boolean returned from validation status
if (IsValid)
{
// successful validation, return empty form
return PartialView("FormPartialView");
}
else
{
// validation failed, return failure status and previously-filled form
return Json(new { invalid = true, form = RenderViewToString(PartialView("FormPartialView", model)) });
}
}
try this and remove the Ajax Helper
$('#reqins').on('click', function () {
let data = $("form :input").serializeArray();
$.ajax({
url: '#Url.Action("RequestInsert", "Home")'
,type: "POST"
,data: data
,success:function (result) {
$("#requestForm").html(result);
}});
});
modify your action to this
public JsonResult RequestInsert()
{
try
{
return Json(new { success = true, result = PartialView("Prtialview") });
}
catch (Exception ex)
{
return Json(new { success = false, result = ex.ErrorMessage });
}
}
and then modify the client side as following
$('#reqins').on('click', function () {
let data = $("form :input").serializeArray();
$.ajax({
url: '#Url.Action("RequestInsert", "Home")'
,type: "POST"
,data: data
,success:function (result) {
if(result.succuss)
{
$("#requestForm").html(result);
}
else
{
alert("Error");
}
}});
});

ValidationMessage and ModelState.AddModelError not working

I want to do cusotm validation and return false and show message in case of validation fail.
In controller below code is used to submit posted data to database.
[HttpPost]
public JsonResult SubmitDa(IList<AdViewModel> s, String section)
{
...........
..........
ModelState.AddModelError("MessageError", "Please enter AttendanceDate");
JSONSubmit r = new JSONSubmit();
r.ErrorCount = iError;
r.errors = errors;
return Json(r, JsonRequestBehavior.AllowGet);
}
Below is the code in view file (cshtml)
#Html.ValidationMessage("MessageError")
.....
$.AJAX call to `SubmitDa` controller's method.
Message is not appearing at "MessageError" validation message. please suggest me what is wrong here.
Thanks
If you want to use the modelstate for errors you shouldn't really be sending a JSON response. Having said that you can handle it by having the controller return JSON only in the case of success, and the page handles the response differently
IE:
[HttpPost]
public ActionResult SubmitDa(IList<AdViewModel> s, String section)
{
...........
..........
ModelState.AddModelError("MessageError", "Please enter AttendanceDate");
JSONSubmit r = new JSONSubmit();
r.ErrorCount = iError;
r.errors = errors;
if (r.ErrorCount != 0)
return Json(r, JsonRequestBehavior.AllowGet);
return View("ViewName", s); // <-- just return the model again to the view,
// complete with modelstate!
}
on the page something like:
<script>
$("#buttonId").click({
$.ajax({
type: "POST",
url: "PostBackURL",
data: $("#formID").serialize(),
success: function (response){
//test for a property in the JSON response
if(response.ErrorCount && response.ErrorCount == 0)
{
//success! do whatever else you want with the response
} else {
//fail - replace the HTML with the returned response HTML.
var newDoc = document.open("text/html", "replace");
newDoc.write(response);
newDoc.close();
}
}
});
});
</script>

Presenting Modal After Form Submission in MVC

I am trying to create a modal that will tell the user their submission was successfully submitted. This works fairly well, but the only problem is I have to declare each of my properties and assign it a value, then in the Json method I have accept all those parameters then do something with them. Is there any way to do this with a ViewModel? Or any otherway that this can be done using a ViewModel?
controller:
public Json Send(string var1, string var2)
{
...
if(valid)
return new Json(true, JsonRequestBehavior.AllowGet);
else
return new Json(false, JsonRequestBehavior.AllowGet);
}
javascript:
function submitData() {
$.ajax({
url: "/Report/Send",
type: "POST",
dataType: "json",
data: { var1 = Model.var1, var2 = Model.var2... },
success: function (data) {
if(data) {
showDialog();
}
else {
$("#errorDiv").load('Report/Error/');
}
},
error: function (somefunction) { }
});
}
Yes, create a ViewModel POCO class:
var myJsonResult = new { result: true };
return Json(myJsonResult);
You can also use a strongly typed ViewModel and return that:
var myJsonResult = new CustomResult { result: true };
return Json(myJsonResult);
Then just check that property on the class in your success function:
success: function (data) {
if(data.result) {
showDialog();
}
else if(!data.result) {
$("#errorDiv").load('Report/Error/');
}
},
EDIT:
You might also want to look at jquery's .serialize() method:
data: $("#myForm").serialize()
This will be useful if you bind your ViewModel to form elements and need to post them back to the server.

getting a return value upon ajax save of new form

I am using ajax to add form data to the database. My add code works great, but I need somehow to grab the newly created ID and use it in my jquery after the save has succeeded.
Here is my save jquery:
$(document).ready(function() {
$("#saveChanges").on("click", function(e) {
var formData = $("form").serialize();
e.preventDefault();
$.ajax({
url: "newListing/",
data: formData,
type: "POST",
success: function (resp) {
debugger;
alert($('#id').val());
$('#listChosen').html("");
$('#listChosen').load("/Listing/SearchListing/" + $('#id').val());
alert("listing added");
},
error: function(xhr, ajaxoptions, thrownError) {
alert(xhr.responseText);
}
});
});
What I am trying to do is expose the newly created ID from newListing and use it when calling the /SearchListing/.
The controller action I call with new listing is as follows:
[HttpPost]
public ActionResult newListing(Listing newList)
{
_listingservice.NewListing(newList);
return View();
}
This action filters through my service layer via interfaces to my repository and eventually makes this call:
try
{
_entities.Listings.Add(newList);
_entities.SaveChanges();
}
catch (Exception)
{
return false;
throw;
}
return true;
upon the savechange() the new ID is available but i dont know how to filter it back down to my success code in the jquery.
Can anyone offer any advice on how I might do this.
Many thanks
You could return the newly saved entity from NewListing. You don't seem to be using the View() that you're currently rendering, so you could just respond with the Id instead:
[HttpPost]
public ActionResult newListing(Listing newList)
{
var entity = _listingservice.NewListing(newList);
return Content(entity.Id.ToString());
}
Then your ajax would receive the id:
...
success: function (id) {
debugger;
alert(id);
$('#listChosen').html("");
$('#listChosen').load("/Listing/SearchListing/" + id);
alert("listing added");
},
...

Return Custom Errors to ajax post error function from JsonResult Method and display it under Validation Summary

I have Action Method of types "JsonResult". I call it using ajax post. I want to return the custom errors from the action method back to ajax post and display those errors as validation Summary.
[HttpPost]
public JsonResult RegisterUser(RegistrationModel model)
{
//if username already exists return custom error to be displayed on view
//under validation summary
// control should go back to error function with message to be displayed.
}
$.ajax({
url: url,
type: 'POST',
dataType: 'json',
data: ko.toJSON(model),
contentType: "application/json; charset=utf-8",
success: function (result) {
success(result)
},
error: function (req, status, error) {
error(req, status, error);
}
});
function success(result) {
//Do Something
}
function error(req, status, error) {
//Display error messages under validation summary.
}
From my understanding, when you do an ajax post, it doesn't care if the Model Validation passed or not, it only cares if it got a response from the server. If an Exception gets thrown from the server, then it will hit your ajax error function.
So what I would do is return a json object that lets me know the validation status.
if(!ModelState.IsValid){
var modelStateErrors = this.ModelState.Keys.SelectMany(key => this.ModelState[key].Errors);
var message = "Please fix the following: " + Environment.NewLine;
foreach (var modelStateError in modelStateErrors)
{
message += modelStateError.ErrorMessage + Environment.NewLine;
}
return Json(new {success = false, response = message})
}
// Do other logic
return Json(new {success = true, response = "Successful message"})
Once you pass this object back, you can do the following Javascript
success: function (result) {
if(result.success === true){
$('#status-div').empty().html('<div class="success">' + result.response + '</div>');
}
if(result.success === false){
$('#status-div').empty().html('<div class="fail">' + result.response + '</div>');
}
}

Resources