0

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; }
    }
user2695433
  • 2,013
  • 4
  • 25
  • 44
  • Your element already exists on the page, so you do not need to re-parse the validator (and doing it for a json value makes no sense anyway) –  Nov 07 '17 at 03:13
  • Its not clear what your expecting to happen. All you controls will be validated when you submit the form –  Nov 07 '17 at 03:16
  • @StephenMuecke I'm trying to Fire the Range validation for the field Quantity , the min quantity entered shall be 1 and the max value should be from the populated POTotalQty field ( this field is populated on dropdown selection) – user2695433 Nov 07 '17 at 05:03
  • @StephenMuecke Html.EditorFor(model => model.Quantity, new { htmlAttributes = new { class = "form-control", type = "number", min = "1", max = Model.POTotalQuantity.ToString() } }) , this was the one I was mentioning, say if I give max =5 staticallyit works . but not when that field value is dynamically populated – user2695433 Nov 07 '17 at 05:06
  • Then you cannot use a `[Range]` attribute. You need to use a conditional validation attribute. Show you model with the attributes you currently have –  Nov 07 '17 at 05:06
  • You could of course update the `max` attribute in the `Quantity` textbox, but that will not give client and server side validation (`min` and `max` attributes have nothing to do with the jquery.validate.js` plugin) –  Nov 07 '17 at 05:08
  • @StephenMuecke . Thanks .Any workaround for this? Shared the model used. I'm using Range in the Razor View as attributes. – user2695433 Nov 07 '17 at 05:12
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/158371/discussion-between-stephen-muecke-and-user2695433). –  Nov 07 '17 at 05:13

1 Answers1

1

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; }