Momin Osama Momin Osama - 17 days ago 15
Ajax Question

Ajax.BeginForm Handling two different onSuccess Response, MVC 5,C#

I am new to Ajax and Jquery so i need you to forgive me if i am trying to do something stupid,
i am working with MVC 5 and Ajax.Beginform,
and what i am trying to do is i have a ajax form i need to validate it with jquery unobtrusive,if i am getting it right the Jquery validation work with ModelState and will return the view back again if is a validation error found, in this case i need to update my form so the validation message appears to the user browser ,for example here is my controller :

[HttpPost]
public ActionResult Index(AddProduct model)
{
if (ModelState.IsValid)
{
// connect to the database save data etc...
return PartialView("~/Views/Shared/_MyModal.cshtml");
}
else
{
return View(model);
}
}


if the ModelState.IsValid i should save the data and return partial view (Bootstrap Modal) indicating that the data has been saved successfully,
else it will return the whole view to display the validation messages and to do that i have to put the TargetId of the ajax form to wrap up the whole ajax form to updated,
and here the ajax form :

<div id="result">
@using (Ajax.BeginForm("Index", new AjaxOptions
{
InsertionMode = InsertionMode.Replace,
UpdateTargetId = "result",
HttpMethod = "POST",
OnBegin = "onBegin();",
OnComplete = "onCompleated();",
OnSuccess = "onSuccess()",
OnFailure = "onFailure()"
}))
{
@Html.ValidationSummary(true)
<div id="form1" class="form-horizontal">
<div class="row">
<div class="form-group">
@Html.LabelFor(m => m.Name, new { @class = "col-md-2 control-label" })
<div class="col-md-10">
@Html.TextBoxFor(m => m.Name, new { @class = "form-control" })
@Html.ValidationMessageFor(m => m.Name, String.Empty, new { @class = "text-danger" })
</div>
</div>
<div class="form-group">
@Html.LabelFor(m => m.Price, new { @class = "col-md-2 control-label" })
<div class="col-md-10">
@Html.TextBoxFor(m => m.Price, new { @class = "form-control" })
@Html.ValidationMessageFor(m => m.Price, String.Empty, new { @class = "form-help form-help-msg text-red" })
</div>
</div>

<div class="form-group">
<button class="btn btn-default col-md-2 col-md-offset-2" type="submit">Save &nbsp;&nbsp;</button>
</div>
</div>
</div>
}
</div>


else i will return a partial view and display it as Bootstrap Modal and i need in this case not to update the ajax form targetId i need to keep it intact and just Displaying the Modal, but the problem is in both situation ModelState.IsValid or Is not Valid all response fires onSuccess Method in ajax form i didn't know these is normal or not, and here is the javascript onsuccess() Method :

function onSuccess() {
$('#myModal').modal('hide')
$("#resultModal").modal({
backdrop: 'static',
keyboard: false
});
$('#resultModal').on('hidden.bs.modal', function (e) {
window.location = "/product";
});
}


$(#'myModal').modal('hide') is a progress Modal i hide it after the posting has finish,and the next step is i show result Modal which i had return it if the Posting execute fine without validation error,
the Problem is :


  • i get to update the form using the UpdatetargetId in the ajax form just fine if validation Error happen to be Exist, but that's happen any way if i am returning Validation Error Or partial view that caring the Modal for me,in both situation the form disappear,and that's something i don't wont to do,
    i need to keep the form in case the return Content was partial view and updated in case ModelStat validation Error, maybe i miss understand everything but if i am, i need some explanation to put me back on track .

  • I did an ugly code and messy and i didn't like in onSuccess() Mehtod as mentioned above, i used event fires when i close my result Modal redirect me again to Index so the form Display again but its not clean and i don't like it, i need something professional if exist.



Thank you in Advance,

Answer

I perfectly understand your problem and I am ready to show you the method that I am using to handle this case.

So because onSuccess method is called every time not depending if ModelState is valid or not , you will need to handle the response a little bit different. So your[HttpPost] method should look like this:

 [HttpPost]
        public ActionResult Index(AddProduct model)
        {
            if (ModelState.IsValid)

            {
                return Json(new {isValid = true, data = this.RenderPartialViewToString("ViewWhenModelStasteIsValid",model,false)});
            }
            else
            {
                return Json(new { isValid = false, data = this.RenderPartialViewToString("ViewWhenModelStasteIsNotValid", model, false) });
            }
        }

public static string RenderPartialViewToString(this Controller controller, string viewName, object model)
        {
            if (string.IsNullOrEmpty(viewName))
            {
                viewName = controller.ControllerContext.RouteData.GetRequiredString("action");

            }
            controller.ViewData.Model = model;

            using (var sw = new StringWriter())
            {
                var viewResult = ViewEngines.Engines.FindPartialView(controller.ControllerContext, viewName);
                var viewContext = new ViewContext(controller.ControllerContext, viewResult.View, controller.ViewData, controller.TempData, sw);
                viewResult.View.Render(viewContext, sw);
                return sw.GetStringBuilder().ToString();
            }
        }

In the view you will need to take off UpdateTargetId from the form and handle it manually on success function.

So your onSuccess function should look like this

function onSuccess(result, ref) {
         if (result.isValid) {
           jQuery("#result).html(result.data);
          } else {
            jQuery("#form1").html(result.data);
        }
    }

Make sure to pass the response data to onSuccess function, so you will need to change on the form from OnSuccess = "onSuccess()" to OnSuccess = "onSuccess(data,this)".

So your form will look like this:

@using (Ajax.BeginForm("Index", new AjaxOptions
  {
InsertionMode = InsertionMode.Replace,
HttpMethod = "POST",
OnBegin = "onBegin();",
OnComplete = "onCompleated();",
OnSuccess = "onSuccess(data,this)",
OnFailure = "onFailure()"
 }))

Hope this is what you need.

Comments