I have 2 fields total quantity which updates on dropdown selection and a field to enter quantity which should be lesser or equal to the total quantity. Dropdown selection fetches the data via ajax call. I understand that dynamically updated values in the DOM needs to be forced to parse validate again. But it seems not be working . All other validations works as normal in the form. Similar questions in SO which I have referred to SO1 SO2 Code tried:
@using (Html.BeginForm())
{
@Html.AntiForgeryToken()
<div class="form-horizontal">
<hr />
@Html.ValidationSummary(true, "", new { @class = "text-danger" })
<div class="form-group">
@Html.LabelFor(model => model.PurchaseOrderID, "PurchaseOrderID", htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-4">
@Html.DropDownListFor(u => u.PurchaseOrderID, Model.PurchaseOrders, "--Select--")
@Html.ValidationMessageFor(model => model.PurchaseOrderID, "", new { @class = "text-danger" })
</div>
</div>
<div class="form-group">
@Html.LabelFor(model => model.POTotalQuantity, htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-4">
@Html.EditorFor(model => model.POTotalQuantity, new { htmlAttributes = new { @class = "form-control", @readonly = "readonly" } })
</div>
</div>
<div class="form-group">
@Html.LabelFor(model => model.Quantity, htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-4">
@Html.EditorFor(model => model.Quantity, new { htmlAttributes = new { @class = "form-control", @type = "number", min = "1", max = Model.POTotalQuantity.ToString() } })
@Html.ValidationMessageFor(model => model.Quantity, "", new { @class = "text-danger" })
</div>
</div>
<div class="form-group">
@Html.LabelFor(model => model.ExpectedDeliveryDate, htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-3">
@Html.EditorFor(model => model.ExpectedDeliveryDate, "{0:dd/mm/yyyy}", new { htmlAttributes = new { @class = "form-control datepicker" } })
@Html.ValidationMessageFor(model => model.ExpectedDeliveryDate, "", new { @class = "text-danger" })
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Create" class="btn btn-primary" />
</div>
</div>
</div>
}
Controller:
public JsonResult PopulatePODetails(int POID)
{
var purchaseOrder = db.PurchaseOrders.Find(POID);
var poTotalQty = db.PurchaseOrderLineItems.Where(p => p.PurchaseOrderID == purchaseOrder.ID).Sum(q => q.Quantity);
// Build an anonymous object
var data = new
{
POTotalQty = poTotalQty
};
return Json(data, JsonRequestBehavior.AllowGet);
}
JS:
$(document).ready(function () {
//Populating PO quantity on PO selection
$('#PurchaseOrderID').change(function () {
if (($(this).val() == "") || ($(this).val() == "0")) {
//need to clear textbox values
$('#POTotalQuantity').val('');
}
else {
var poId = $(this).val();
var url = '@Url.Action("PopulatePODetails", "DeliverySchedules")';
$.getJSON(url, { POID: poId }, function (response) {
$('#POTotalQuantity').val(response.POTotalQty);
$.validator.unobtrusive.parse($(response));
});
}
});
});
Model:
public class DeliveryScheduleVM
{
public int ID { get; set; }
//omitted other properties
public IEnumerable<SelectListItem> PurchaseOrders { get; set; }
[DisplayName("PO Total Qty")]
public int POTotalQuantity { get; set; }// this is used as the upper limit
[Required]
public int Quantity { get; set; }
}
First to clear up some misconceptions you have.
When you reparse the $.validator
, your instructing jquery.validate.unobtrusive.js
to parse the DOM and read the data-val-*
attributes in your form controls (generated by your properties validation attributes) and add the rules to jquery.validate.js
. That was already done when the form was first loaded, and is only necessary again when you dynamically add new form controls (e.g. via ajax) which your not doing (your control for Quantity
already exists). In any case, you need to parse the <form>
element, not a json object. Refer this answer for the correct usage.
Second, the min
and max
attributes are for HTML-5 validation only and have nothing to do with jQuery validation. In fact they will not even work since jquery.validate.js
adds the novalidate="novalidate"
attribute to your <form>
element since they do not play well together.
What you need for both client and server side validation is a conditional ValidationAttribute
that implements IClientValidatable
, and associated scripts so that the value of Quantity
can be compared with the value of POTotalQuantity
. For a good guide to writing your own conditional validation attributes, I recommend The Complete Guide To Validation In ASP.NET MVC 3 - Part 2. In your case you might write an attribute that is used like
[Required]
[Bewteen(1, "POTotalQuantity")]
public int Quantity { get; set; }
You can also use the conditional validation attributes from the foolproof plugin if you do not want to write your own.
Download the package (and include the mvcfoolproof.unobtrusive.js
script in your view) and decorate you property with
[Required]
[Range(1, int.MaxValue)] // for minimum value
[LessThanOrEqualTo("POTotalQuantity", ErrorMessage = "The quantity must be less than or equal to the value of POTotalQuantity")]
public int Quantity { get; set; }