2

Using the RangeAttribute with a type of DateTime to to specify a minimum and maximum value for a date property does not work. A question on how to work around this has been asked here, with the highest-voted solution being:

There is no need to disable jQuery date validation (and that is likely to cause other issues). You just need to override the range method of the $.validator.

By default, it works with numeric values (and then falls back to a string comparison), so you can add the following script (after jquery.validate.js and jquery.validate.unobtrusive.js, but not wrapped in $(document).ready

$.validator.methods.range = function(value, element, param) {
    if ($(element).attr('data-val-date')) {
        var min = $(element).attr('data-val-range-min');
        var max = $(element).attr('data-val-range-max');
        var date = new Date(value).getTime();
        var minDate = new Date(min).getTime();
        var maxDate = new Date(max).getTime();
        return this.optional(element) || (date >= minDate && date <= maxDate);
    }
    // use the default method
    return this.optional( element ) || ( value >= param[ 0 ] && value <= param[ 1 ] );
};


Can someone please help me understand how to implement this solution? (My HTML & Javascript knowledge is embarrassingly poor, so any help is appreciated.)


From the description of the solution, I would assume I want this script to end up at the bottom of the generated HTML, so I have tried adding it to my _ValidationScriptsPartial.cshtml, so I now have:

<script src="~/lib/jquery-validation/dist/jquery.validate.min.js"></script>
<script src="~/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.min.js"></script>
<script type="text/javascript">
    $.validator.methods.range = function(value, element, param) {
    if ($(element).attr('data-val-date')) {
        var min = $(element).attr('data-val-range-min');
        var max = $(element).attr('data-val-range-max');
        var date = new Date(value).getTime();
        var minDate = new Date(min).getTime();
        var maxDate = new Date(max).getTime();
        return this.optional(element) || (date >= minDate && date <= maxDate);
    }
    // use the default method
    return this.optional( element ) || ( value >= param[ 0 ] && value <= param[ 1 ] );
};
</script>

The script now appears at the bottom of the generated HTML, however it doesnt seem to affect the validation error that appears on the form.

devklick
  • 2,000
  • 3
  • 30
  • 47
  • Did u add the following code in your web.config file? – Maddy89 Feb 23 '20 at 02:18
  • do you have it in a `@section Scripts { }` block? scripts won't run outside of that... – mvermef Feb 23 '20 at 07:10
  • @Maddy89 I dont think it should be necesary to create a `web.config` file when working with dotnet core MVC. However, I've added these settings via `appsettings.json`, which hasnt made any difference. I've also set `HtmlHelperOptions.ClientValidationEnabled = true` when configuring services. I can tell it's deffo denabled, as setting it to false results in no validation taking client side validation taking place – devklick Feb 23 '20 at 14:53
  • @mvermef I have added above code to my `_ValidationScriptsPartial.cshtml`, and within my view, I have `@section Scripts { @{await Html.RenderPartialAsync("_ValidationScriptsPartial");} }`, but I still have the same problem. – devklick Feb 23 '20 at 14:55

1 Answers1

2

The script now appears at the bottom of the generated HTML, however it doesnt seem to affect the validation error that appears on the form.

Based on the code that you provided, I suspect that it might not reach into if ($(element).attr('data-val-date')) code block, which casue your customized client-side validation function does not work as expected.

Please check the source code of the corresponding element and make sure it has data-val-date attribute.

Besides, if the element does not include data-val-date="true" as below, you can modify the code like below to make the code snippet (within if condition block) could be reached while the function is triggered by that specific element.

StartDateTime property

[Range(typeof(DateTime), "1/1/2020", "2/29/2020")]
public DateTime StartDateTime { get; set; }

Html source code of that specific element

enter image description here

Modified code to check if current element is that specific element with if $(element).attr('id') == "StartDateTime")

@section Scripts {
    @{await Html.RenderPartialAsync("_ValidationScriptsPartial");}

<script>
    $.validator.methods.range = function (value, element, param) {

        //console.log(param);

        if ($(element).attr('id') == "StartDateTime") {
            var min = $(element).attr('data-val-range-min');
            var max = $(element).attr('data-val-range-max');
            var date = new Date(value).getTime();
            var minDate = new Date(min).getTime();
            var maxDate = new Date(max).getTime();
            console.log(minDate + " | " + maxDate + " | " + date);

            return this.optional(element) || (date >= minDate && date <= maxDate);
        }
        // use the default method
        return this.optional(element) || (value >= param[0] && value <= param[1]);
    }
</script>
}
Fei Han
  • 26,415
  • 1
  • 30
  • 41
  • You are absolutely spot on! The statement `if ($(element).attr('data-val-date'))` was never true, as the `data-val-date` attribute did not exist - the attribute was simply called `data-val`. After changing the JS to check for this, and to check the type is date, the validation works as expected. Thanks for your help! – devklick Feb 25 '20 at 18:01