Reputation: 443
I have a search form, which will do some client side validation, call the server action, do some server side validation, and then return either the original view (with the modelstate errors) OR the search results.
For this approach to work, i would need to render the view to a string, and return a Json result. I could probably do that with one of the answers in this question: Render a view as a string
However, if i'm having to implement my own 'RenderView' type function, is this really the best way to do this? Or is there a better design decision for implementing this kind of functionality? Any help would be greatly appreciated.
An abstraction of the code is listed below for reference;
Controller:
public ActionResult Index()
{
return View(new SearchModel());
}
public ActionResult Search(SearchModel criteria)
{
if (!ModelState.IsValid)
return Json(new { HasErrors = true, Result = RenderViewToString("Index", criteria) });
var results = {Do Search...};
return PartialView("SearchResults", results);
}
View:
@using(Html.BeginForm(...))
{
{form fields...}
{submit button...}
}
<div id="search-results"></div>
<script type="text/javascript">
$(document).on("submit", "form", function(e) {
if (!$(this).valid()) return false;
e.preventDefault(); // Submit the form with ajax instead.
$.ajax({
url: this.action,
type: this.method
data: $(this).serialize(),
success: function(data) {
if (data.HasErrors) {
$(document).html(data.Result);
}
else {
$("#search-results").html(data);
}
}
});
});
</script>
Upvotes: 2
Views: 1665
Reputation: 443
I've marked Kiyarash's answer as correct, as it put me on the right track. Here is what i actually used though: (Please note that this will only show the last error for each field - I will be adding some logic into it, so that it shows multiple error messages).
if (!ModelState.IsValid)
{
return Json(new
{
HasErrors = true,
Errors = ModelState.ToDictionary(
ms => ms.Key,
ms => ms.Value.Errors.Select(e => e.ErrorMessage).ToArray()
).Where(ms => ms.Value.Count() > 0)
}, JsonRequestBehavior.AllowGet);
}
$.ajax({
...
success: function(data) {
if (data.HasErrors) {
showErrorMessages(data.Errors, $("form"));
}
else {
$("#search-results").html(data);
}
}
});
function showErrorMessages(errors, context) {
$.each(errors, function (i, error) {
$("[data-valmsg-for='" + error.Key + "']", context).text(error.Value)
.removeClass("field-validation-valid")
.addClass("field-validation-error");
});
}
Upvotes: 4
Reputation: 1013
First of all you need this jquery function to add error in validation summary
$.fn.addNewErrorMessage = function (message) {
$(this).find('.validation-summary-valid').removeClass('validation-summary-valid')
.addClass('validation-summary-errors');
$(this).find(".validation-summary-errors ul").append("<li>" + message + "</li>");
}
Then you need make a list of error and return it as a JSON format like this code in action.
if (!modelState.IsValid)
{
var errors = ModelState.ToDictionary(kvp => kvp.Key,
kvp => kvp.Value.Errors
.Select(e => e.ErrorMessage).ToArray())
.Where(m => m.Value.Count() > 0);
return Json(new {HasErrors = true,Errors = errors});
}
After that in success function in ajax use addNewErrorMessage function to show error messages
$.ajax({
url: this.action,
type: this.method
data: $(this).serialize(),
success: function(data) {
if (data.HasErrors) {
for(int i; i<data.Errors.length)
{
$('form').addNewErrorMessage(data.Errors[i].Value);
}
}
else {
$("#search-results").html(data);
}
}
Upvotes: 2