DatePicker 1 Must be before DatePicker 2

1 Answer 6616 Views
Date/Time Pickers
Ian
Top achievements
Rank 2
Ian asked on 25 Jul 2013, 04:21 PM
Give how awesome Kendo is I thought I'd ask. (I haven't see it in the docs)

Is there a way, in MVC, to enforce that DatePicker 2 is before DatePicker 1. It's a fairly common validation for forms with a From and To date.

Thanks

1 Answer, 1 is accepted

Sort by
0
Dimo
Telerik team
answered on 26 Jul 2013, 11:42 AM
Hi Ian,

Please refer to

http://demos.kendoui.com/web/datepicker/rangeselection.html

 

Regards,
Dimo
Telerik
Join us on our journey to create the world's most complete HTML 5 UI Framework - download Kendo UI now!
Atlas
Top achievements
Rank 1
commented on 03 Oct 2013, 05:17 PM

The demo doesn't appear to work. I wrote my own code to resolve the issue:

$(function () {
    function checkDates() {
        if (startDate.val() != '' && endDate.val() != '') {
            if (Date.parse(startDate.val()) > Date.parse(endDate.val())) {
                alert('End date should be before start date');
                endDate.val(startDate.val());
            }
        }
    }
     
    var startDate = $("#startDate").kendoDatePicker({
        change: checkDates
    });
    var endDate = $("#endDate").kendoDatePicker({
        change: checkDates
    });
 
    $("#startDate").kendoValidator({
        rules: {
            date: function (input) {
                var d = kendo.parseDate(input.val());
                return d instanceof Date;
            }
        }
    });
 
    $("#endDate").kendoValidator({
        rules: {
            date: function (input) {
                var d = kendo.parseDate(input.val());
                return d instanceof Date;
            }
        }
    });
});
Greg
Top achievements
Rank 1
commented on 03 Oct 2013, 05:19 PM

I want to perform this validation on two dates that are in a Grid that uses the Default Popup Editor (which automatically applies DatePickers to the two date fields). The referenced example has easy to reference input fields. With the popup editor, I don't know how to do this.

Can anyone point me the right direction? Thanks.
Dimo
Telerik team
commented on 04 Oct 2013, 07:49 AM

@Atlas

The online demo works as expected, but uses a different approach, compared to your implementation - each DatePicker change handler limits the range of valid values of the other DatePicker.

@Greg 

One option is to use an edit form template

http://docs.kendoui.com/api/web/grid#configuration-editable.template

Another option is to use two custom editors with preset IDs and attach change handlers.

http://demos.kendoui.com/web/grid/editing-custom.html

The best option is probably to use custom validation rules in the model. The following is based on the Grid popup editing demo and defines a dummy requirement that the UnitPrice should be greater than UnitsInStock.

http://demos.kendoui.com/web/grid/editing-popup.html

Note that the custom validation rule is executed for every field, so you first check which field is the current one, and also, return true for the unrelated fields, and true/false for the related fields.


schema: {
    model: {
        id: "ProductID",
        fields: {
            ProductID: { editable: false, nullable: true },
            ProductName: { validation: { required: true } },
            UnitPrice: { type: "number",
                validation: {
                    required: true,
                    min: 1,
                    custom: function(input) {
                        if (input && (input.attr("name") == "UnitPrice" || input.attr("name") == "UnitsInStock")) {
                            // add custom validation message
                            input.attr("data-custom-msg", "foo");
                            // retrieve widgets
                            var unitPriceInput = input.closest(".k-edit-form-container").find("[name='UnitPrice']").data("kendoNumericTextBox");
                            var unitsInStockInput = input.closest(".k-edit-form-container").find("[name='UnitsInStock']").data("kendoNumericTextBox");
                            // validate
                            if (unitPriceInput.value() < unitsInStockInput.value()) {
                                return false;
                            } else {
                                return true;
                            }
                        }
                        // return true for unrelated fields
                        return true;
                    }
                }
            },
            Discontinued: { type: "boolean" },
            UnitsInStock: { type: "number", validation: { min: 0, required: true } }
        }
    }
}


Regards,
Dimo
Telerik
Join us on our journey to create the world's most complete HTML 5 UI Framework - download Kendo UI now!
Greg
Top achievements
Rank 1
commented on 04 Oct 2013, 07:41 PM

Dimo: Thank you. Your final suggestion worked well.

I have one more question to refine the validation though. I would like to ignore the time portion of the dates I am comparing.

e.g. 10/01/2013 16:00:00 is technically less than 10/01/2013 17:00:00, but I want to simply compare 10/01/2013 and 10/01/2013 and determine them to be equal (and fail the test in my code below).

This is the field definition I have running. This works except it includes the time in the comparison.

            contractStartDate: {
              type: "date", validation: {
                validateContractStartDate: function (input) {
                  // Check that input field is the one we want to validate. This fires for every field.
                  if (input && (input.attr("name") == "contractStartDate")) {
                    // Retrieve widgets.
                    var contractEndDateInput = input.closest(".k-edit-form-container").find("[name='contractEndDate']").data("kendoDatePicker");
                    var contractStartDateInput = input.closest(".k-edit-form-container").find("[name='contractStartDate']").data("kendoDatePicker");

                    // Validate
                    var s = contractStartDateInput.value();
                    var e = contractEndDateInput.value();
                    
                    if (e <= s) {
                      input.attr("data-validateContractStartDate-msg", "Start Date must be earlier than End Date");
                      return false;
                    } else
                      return true;
                  } else
                    // return true for unrelated fields
                    return true;
                }
              }
            },

            contractEndDate: {
              type: "date", validation: {
                validateContractEndDate: function (input) {
                  // Check that input field is the one we want to validate. This fires for every field.
                  if (input && (input.attr("name") == "contractEndDate")) {
                    // Retrieve widgets.
                    var contractEndDateInput = input.closest(".k-edit-form-container").find("[name='contractEndDate']").data("kendoDatePicker");
                    var contractStartDateInput = input.closest(".k-edit-form-container").find("[name='contractStartDate']").data("kendoDatePicker");

                    // Validate
                    var s = contractStartDateInput.value();
                    var e = contractEndDateInput.value();

                    if (e <= s) {
                      input.attr("data-validateContractEndDate-msg", "End Date must be later than Start Date");
                      return false;
                    } else
                      return true;
                  } else
                    // return true for unrelated fields
                    return true;
                }
              }
            },
Dimo
Telerik team
commented on 07 Oct 2013, 07:20 AM

Hi Greg,

You have two standard Javascript Date objects. How should you compare them while ignoring the time portions?

Regards,
Dimo
Telerik
Join us on our journey to create the world's most complete HTML 5 UI Framework - download Kendo UI now!
Greg
Top achievements
Rank 1
commented on 07 Oct 2013, 01:25 PM

Sorry for the noob question... The answer is:

                    var s = contractStartDateInput.value();
                    var e = contractEndDateInput.value();

                    var s1 = new Date(s.toDateString());
                    var e1 = new Date(e.toDateString());

                    if (e1 <= s1) {
Antony
Top achievements
Rank 1
Iron
commented on 28 May 2017, 03:34 AM

I found that the demo code did work - beautifully! As soon as a date is selected in the first datepicker, the second datepicker only shows dates for the day after that.

I used the javascript verbatim from the demo on the following view code:

@(Html.Kendo().DatePickerFor(m => m.main.LeaveStart)
          .Name("start")
          .Events(e => e.Change("startChange"))
)
 
@(Html.Kendo().DatePickerFor(m => m.main.LeaveEnd)
          .Name("end")
          .Events(e => e.Change("endChange"))
 )

 

Antony
Top achievements
Rank 1
Iron
commented on 28 May 2017, 07:27 AM

Correction to my post of 3 hours ago - since my DatePicker is bound to a data model, using the .Name property causes an error. For the View all I need is:

@(Html.Kendo().DatePickerFor(m => m.main.LeaveStart)
          .Events(e => e.Change("startChange"))
)
and similar for LeaveEnd.
And for the JavaScript part, it is as in http://demos.telerik.com/aspnet-mvc/datepicker/rangeselection

but with 

var endPicker = $("#main_LeaveStart").data("kendoDatePicker"),

instead of

var endPicker = $("#end").data("kendoDatePicker"),

Michael
Top achievements
Rank 1
commented on 19 Nov 2017, 07:26 AM

Hi,

I have the same issue, I use the function change in the date-pickers and it's great.

but also I want to validate it when the user enter a date by writing or pasting.

how do I need to do it through the kendo validation?

 

my html

@using (Ajax.BeginForm("SaveNewProject", "Project", new AjaxOptions { OnSuccess = "onProjectSuccess" }, new { id = "projectForm" }))
{
    <div class="form-horizontal" id="tempPage" style="margin-top:20px">

        @Html.AntiForgeryToken()
        @Html.ValidationSummary(true, "", new { @class = "text-danger" })

        @Html.HiddenFor(model => model.ProductID)
        <div class="form-group" id="tempPage">
            @Html.LabelFor(model => model.Name, htmlAttributes: new { @class = "control-label col-md-2" })

            <div class="col-md-6 col-sm-6">
                @Html.Kendo().TextBoxFor(model => model.Name)
                @Html.ValidationMessageFor(model => model.Name, "", new { @class = "text-danger" })

            </div>
        </div>

        <div class="form-group" id="tempPage">
            @Html.LabelFor(model => model.CodeReviewerID, htmlAttributes: new { @class = "control-label col-md-2" })

            <div class="col-md-6 col-sm-6">
                @(Html.Kendo().DropDownListFor(model => model.CodeReviewerID)
            .Name("CodeReviewerID")
            .HtmlAttributes(new { style = "width:220px;" })
            .OptionLabel("Select Code Reviewer...")
            .DataValueField("ID")
            .DataTextField("Name")
            .BindTo(Model.Developers))
                @Html.ValidationMessageFor(model => model.CodeReviewerID, "", new { @class = "text-danger" })
            </div>
        </div>


        <div class="form-group" id="tempPage">
            @Html.LabelFor(model => model.LeaderID, htmlAttributes: new { @class = "control-label col-md-2" })

            <div class="col-md-6 col-sm-6">
                @(Html.Kendo().DropDownListFor(model => model.LeaderID)
            .Name("LeaderID")
            .HtmlAttributes(new { style = "width:220px;" })
            .OptionLabel("Select Leader...")
            .DataValueField("ID")
            .DataTextField("Name")
            .BindTo(Model.Developers))
                @Html.ValidationMessageFor(model => model.LeaderID, "", new { @class = "text-danger" })
            </div>
        </div>


        <div class="form-group" id="tempPage">
            @Html.LabelFor(model => model.ActualStartDate, htmlAttributes: new { @class = "control-label col-md-2" })

            <div class="col-md-6 col-sm-6">
                @(Html.Kendo().DatePickerFor(model => model.ActualStartDate)
                           .Name("ActualStartDate")
                           .Format("MM/dd/yyyy")
                           .Value(DateTime.Now)
                           .Events(e => e.Change("startChangeActual").Open("startActualOpen")))
                @Html.ValidationMessageFor(model => model.ActualStartDate, "", new { @class = "text-danger" })

            </div>
        </div>

        <div class="form-group" id="tempPage">
            @Html.LabelFor(model => model.ActualEndDate, htmlAttributes: new { @class = "control-label col-md-2" })

            <div class="col-md-6 col-sm-6">
                @(Html.Kendo().DatePickerFor(model => model.ActualEndDate)
                           .Name("ActualEndDate")
                           .Format("MM/dd/yyyy")
                           .Value(DateTime.Now)
                           .Events(e => e.Change("endChangeActual").Open("endActualOpen")))
                @Html.ValidationMessageFor(model => model.ActualEndDate, "", new { @class = "text-danger" })

            </div>
        </div>




        <div class="container-fluid" style="padding-top:10px">
            <hr id="newProjectHR" />
        </div>
        <div id="buttonPanel">
            <input type="submit" value="save" class="k-button" id="btn_save_project" />
        </div>
    </div>

}

my js:

$(function () {
    var validator = $("#projectForm").kendoValidator().data("kendoValidator");
});

function startChangeActual() {
    var endPicker = $("#ActualEndDate").data("kendoDatePicker"),
        startDate = this.value();

    if (startDate) {
        startDate = new Date(startDate);
        startDate.setDate(startDate.getDate());
        endPicker.min(startDate);
    }
}

function endChangeActual() {
    var startPicker = $("#ActualStartDate").data("kendoDatePicker"),
        endDate = this.value();

    if (endDate) {
        endDate = new Date(endDate);
        endDate.setDate(endDate.getDate());
        startPicker.max(endDate);
    }
}

thanks

 

 

Stefan
Telerik team
commented on 21 Nov 2017, 11:53 AM

Hello, Michael,

Currently, this can be achieved with a custom logic on the change event of the DatePicker. It will require subscribing to the paste event of the input element as this will provide the needed information.

I made a Dojo example demonstrating how this can be achieved:

https://dojo.telerik.com/eyaYAT

I hope this is helpful.

Regards,
Stefan
Progress Telerik
Try our brand new, jQuery-free Angular components built from ground-up which deliver the business app essential building blocks - a grid component, data visualization (charts) and form elements.
Tags
Date/Time Pickers
Asked by
Ian
Top achievements
Rank 2
Answers by
Dimo
Telerik team
Share this question
or