I am using the IGrid and batch updating. I have a page with the following...
@Html.ValidationSummary()@(Html.Infragistics().Grid(Model.GetAllGmiProducts()).UpdateUrl(Url.Action("EditingSaveChanges", "Gmi"))
... rest of grid here
My controller method looks like this...
[
ActionName("EditingSaveChanges")]public ActionResult EditingSaveChanges(GmiModel model){
GridModel m = new GridModel(); List<Transaction<GmiProduct>> transactions = m.LoadTransactions<GmiProduct>(HttpContext.Request.Form["ig_transactions"]); //perform some validation on 'transactions' here, add a model error to modelState if that validation fails
ModelState.AddModelError(string.Empty, "Error occurred!"); if (!model.ModelState.IsValid) { return View("Index", model); }
JsonResult result = new JsonResult(); Dictionary<string, bool> response = new Dictionary<string, bool> { { "Success", true} }; result.Data = response; return result;
}
My problem is that the validation summary never displays my error messages. I assume this is because the grid is doing an ajax call to the controller method, so the page is never fully redrawn.
What is the best way to deal with this? How can I get the ValidationSummary to be redrawn when the grid update does not return success? I have also tried throwing exceptions from inside my controller method and responding to the requestError event of the grid, but I have been unsuccessful in getting that to work as well.
Hi Mike,I'm afraid that we don't provide out-of-the-box integration between the ASP.NET MVC ValidationSummary and the controller action that's used for the UpdateUrl option of our MVC grid because that action is meant to be called via AJAX in order to provide a response for the jQuery-based igGrid on the client-side.The action being used for the UpdateUrl doesn't seem to be friendly enough in order to get the MVC validation summary to display (perhaps I've missed something obvious?)So, as a workaround, I suggest the following (yes, it involves jumping through some hoops).Step #1: Get the UpdateUrl action to report a problem like so:
public ActionResult EditingSaveChanges() { DevelopmentDBEntities context = new DevelopmentDBEntities(); IQueryable<VirtualMachines> virtualMachines = from v in context.VirtualMachines select v; ViewData["GenerateCompactJSONResponse"] = false; GridModel m = new GridModel(); List<Transaction<MyVirtualMachine>> transactions = m.LoadTransactions<MyVirtualMachine>(HttpContext.Request.Form["ig_transactions"]); //perform some validation on 'transactions' here, add a model error to modelState if that validation fails bool isSuccessful = false; string errorMessage = "Error occurred while processing the transactions for the igGrid!"; JsonResult result = new JsonResult(); // [BorislavT] Rather than add the error to the ModelState here, I'll just let grid know that the server-side operation(s) were unsuccessful. // The view will receive the error message and post //ModelState.AddModelError(string.Empty, errorMessage); //if (!ModelState.IsValid) if (isSuccessful) { Dictionary<string, bool> successResponse = new Dictionary<string, bool> { { "Success", true } }; result.Data = successResponse; } else { Dictionary<string, string> failureResponse = new Dictionary<string, string> { { "Failure", errorMessage} }; result.Data = failureResponse; } return result; }
Step #2: On the client, intercept the response and see if it's about a failure (using the jQuery's ajaxSuccess()) and if so, call the ValidationSummaryaction:
<script type="text/javascript"> $(function () { $('#ValidationSummary').ajaxSuccess(function (evt, jqXHR, ajaxOptions) { if (ajaxOptions.url.indexOf("EditingSaveChanges") != -1) { var response = JSON.parse(jqXHR.responseText); if (response["Failure"] !== undefined) { $('#ValidationSummary').load('@Url.Content("~/Chaining/ValidationSummary")', { errorMessage: response.Failure }); } } }); }); </script>
Step #3: Report the error into the ModelState inside the ValidationSummaryaction:
public ActionResult ValidationSummary(string errorMessage) { ModelState.AddModelError(string.Empty, errorMessage); if (Request.IsAjaxRequest()) { return PartialView("Partial/ValidationSummary"); } else { return View(); } }
The partial view ValidationSummary(I've placed it in a folder called "Partial") simply contains the line @Html.ValidationSummary(true)
I've attached a working MVC project to my reply that illustrates the combination of these steps.PS: I'm using a virtual directory on which I host the Infragistics JS and CSS files so feel free to update the references to your liking. Also, the sample I've attached is configured to use the MVC DLL, JS and CSS files for the 2011.2 volume release, but everything works perfectly with the 2012.1 files as well.Cheers!Borislav
Thanks for the replies.. My posting was written quickly and therefore I don't think I was quite clear in what I am trying to accomplish. When doing a delete of a record I am trying to capture any constraint violations and display a friendly message to the user. So, I want to capture server side exceptions that occur while attempting to update the batch of transactions... not client side data validation. I actually was able to piece together a solution on my own that somewhat lines up with Borislav's answer.
I have created a form on my page and a hidden field within that form.
<form id="gmiProductForm" action="@Url.Action("SaveChanges", "Gmi")"><button type="submit" value="Save" title="Save" name="saveChanges" id="saveChanges" class="actionButton">Savebutton><button id="cancelChanges" class="actionButton" type="button">Cancelbutton><div id="errorDiv" style="display: none">Errordiv><div id="successDiv" style="display: none; color: red; font-weight: bold; margin: 5px;">Changes were successfully saved.div><input type="hidden" id="transactionList" />
... grid definition etc...
Next, I put some JavaScript in place to manually capture the transactions from the grid into my hidden field when anything changes.
grid.bind("iggridupdatingrowdeleted", function(e, args) { $("#cancelChanges").igButton("option", "disabled", false); $("#saveChanges").igButton("option", "disabled", false); var transactions = $("#grid1").igGrid("transactionsAsString"); $("#transactionList").val(transactions);});
grid.bind("iggridupdatingrowadded", function(e, args) { $("#cancelChanges").igButton("option", "disabled", false); $("#saveChanges").igButton("option", "disabled", false); var transactions = $("#grid1").igGrid("transactionsAsString"); $("#transactionList").val(transactions);});
grid.bind("iggridupdatingeditrowended", function(e, args) { if(args.update) { $("#cancelChanges").igButton("option", "disabled", false); $("#saveChanges").igButton("option", "disabled", false); var transactions = $("#grid1").igGrid("transactionsAsString"); $("#transactionList").val(transactions); }});
And... another piece of JavaScript to override the submit behaviour of the form...
$(function() { $('#gmiProductForm').submit(function() { $.post('@Url.Action("SaveChanges", "Gmi")', { transactionList: $("#transactionList").val() }, function (result) { if (result.toString().indexOf("Success") == -1) { $('#successDiv').hide(); $('#errorDiv').html(result); $('#errorDiv').fadeIn(1500); } else { $("#cancelChanges").igButton("disable"); $("#saveChanges").igButton("disable"); $('#errorDiv').hide(); $('#successDiv').fadeIn(1500).fadeOut(6000); $("#grid1").igGrid("commit"); }});
The transaction list gets posted with the form, and the response from the post is checked for 'Success'. The UI is updated depending on the outcome.
And finally my controller method that handles the batch update.
public ActionResult SaveChanges(GmiModel model, string transactionList){ if (!string.IsNullOrEmpty(transactionList)) { GridModel gridModel = new GridModel(); List<Transaction<GmiProduct>> transactions = gridModel.LoadTransactions<GmiProduct>(transactionList); using (GmiProductTask gmiProductTask = new GmiProductTask()) { gmiProductTask.Save(model.ModelState, transactions.NewAndUpdated(), transactions.Deleted()); }
if(!model.ModelState.IsValid) return Content(model.ValidationSummary.ToHtmlString(), "text/html");
return Content("Success", "text/html");
My model has it's own implementation of ModelState, which will return a list of errors the same as the built in ModelState. In the save method of my task errors get added to the ModelState if they occur, namely constraint violations on deletes.