I am working in MVC5
and using a combination of client and server validation. For this particular issue I am using remote validation.
The Razorview:
<div id="studentStatus" name="studentStatus">
@using (Html.BeginForm("StudentStatus", "StudentStatus", FormMethod.Post, new { id = "studentStatusForm", data_timer = 240000 }))
{
@Html.HiddenFor(x => x.CurrentStudentSepId, new { @class = "hideMe" })
<div class="row">
<h2 class="col-md-12 topSectionHeader">
@StaffPortalResources.Section_StudentStatus
<span class="savedStatus"></span>
</h2>
</div>
<span class="errorNotification"></span>
<div class="questionGroup form-group">
<div class="row margin-btm-sm">
<div class="col-md-4">
@Html.LabelFor(x => x.StudentStatusId)
@if (Model.IsReadOnly)
{
<div>@Html.DisplayFor(x => x.StudentStatusId)</div>
@Html.HiddenFor(x => x.StudentStatusId)
}
else
{
@Html.CustomComboBoxFor(x => x.StudentStatusId, (new { @class = "statusChangeValidationHandler", data_action = "GetStudentEditableStatuses", data_controller = "Lookup" }))
}
@Html.ValidationMessageFor(x => x.StudentStatusId)
</div>
}
The model:
public sealed class StudentStatusSectionViewModel : SectionViewModel
{
[Display(Name = "Status", ResourceType = typeof(StaffPortalResources))]
[SelectMustExist(true, ErrorMessageResourceType = typeof (StaffPortalResources), ErrorMessageResourceName = "StudentStatus_InvalidSelection")]
[Remote("ValidateStudentStatus", "StudentStatus", AdditionalFields = "CurrentStudentSepId")]
public string StudentStatusId { get; set; }
public bool DoNotReenroll { get; set; }
}
The controller:
public JsonResult ValidateStudentStatus(StudentStatusSectionViewModel model)
{
var errors = _studentStatusSectionAdapter.ValidateStudentStatus(model.CurrentStudentSepId, model.StudentStatusId);
if (errors != null && errors.Any())
{
var currentStatus = _studentStatusSectionAdapter.Get(model.CurrentStudentSepId).StudentStatusId;
Response.AddHeader("status", currentStatus);
return Json(string.Join("</br>", errors), JsonRequestBehavior.AllowGet);
}
return Json(true, JsonRequestBehavior.AllowGet);
}
The remote validation .complete() function:
scope.initializeStudentStatusDropdown = function() {
var $element = $('#studentStatusForm').find('input.statusChangeValidationHandler[data-role="combobox"]');
$element.rules().remote.complete = function (xhr) {
if (xhr.responseText !== 'true')
window.Registration.StudentStatus.fixStudentStatusDropdown($element, xhr.getResponseHeader);
}
}
scope.fixStudentStatusDropdown = function($element,responseHeader) {
$element.kVal(responseHeader('status'));
}
The jquery used to wire validation on change event:
scope.initializeAutoSave = function (form, callBack) {
var $form = $(form);
$form.on("change", "input:not(.ignoreAutoSave)", queueForm);
$form.on("change", "textarea:not(.ignoreAutoSave)", queueForm);
window.Validation.initializeValidator($form);
callBacks[$form.attr('id')] = callBack || function() {};
}
The queueForm method:
function queueForm(e) {
if ($(e.target).valid()) {
var $form = $(e.target).closest("form");
var timer = $form.data("timer");
autoSaveQueue[$form.attr("id")] = { $form: $form, timer: timer, attempt: 0 };
}
}
When tracing through the code after changing the value in the dropdown, the change event fires and calls the queueForm function. the valid()
call evaluates to true before the remote validation happens.
It is not until after I step over 'if ($(e.target).valid())
' line, and it evaluates to true and steps into the if block. Then it jumps into the remote ValidateStudentStatus
function in my controller.
Have I done something wrong here? Am I misunderstanding how the remote validation works?
Any insight or help would be greatly appreciated!