Jo Smo
Jo Smo

Reputation: 7169

How to validate a date with 3 input fields?

I have 3 input fields: year, month and day. I want to validate that the entered date is valid. For example, if someone enters "2016-02-31", an error should be returned.

My problem is that i can't use 1 input field for a DateTime, because the end-user needs to enter a lot of dates, and with 3 inputs, he enters them a lot faster, because he can navigate to the next input field using the TAB key on his keyboard faster.

Or if someone has a better solution, i would be happy to hear it.

EDIT: I need client and server side validation.

Upvotes: 0

Views: 807

Answers (2)

user3559349
user3559349

Reputation:

You will first need to start with a view model to represent your dates

public class DateVM
{
    public DateVM() { } // default constructor required by the DefaultModelBinder
    public DateVM(DateTime date) // useful if your editing existing dates
    {
        Date date.Date;
        Day = date.Day;
        Month = date.Month;
        Year = date.Year;
    }
    public int Day { get; set; }
    public int Month { get; set; }
    public int Year { get; set; }
    [Required(ErrorMessage = "The values for the date are not valid")]
    public DateTime Date { get; set; }
}

and then the main view model would contain a public List<DateVM> Dates {get; set; } property.

While it would be possible to create a custom ValidationAttribute that implements IClientValidatable, (refer The Complete Guide to Validation-in-ASP.NET-MVC-3 Part-2 for a good guide to implementing one) it presents a few design problems such as which property do you apply the attribute to?, what happens when one of the other properties is not edited? etc.

Instead, I recommend you just include your own scripts to handle the .change() events of each control and validate the date (and display an error message if appropriate), and also handle the forms .submit() event to cancel the post if invalid.

Your part of the view for editing the dates would need to be

for(int i = 0; i < Model.Dates.Count; i++)
{
    <div class="date-container">
        @Html.LabelFor(m => m.Dates[i].Year)
        @Html.TextBoxFor(m => m.Dates[i].Year, new { @class = "year" })
        @Html.ValidationMessageFor(m => m.Dates[i].Year)
        @Html.LabelFor(m => m.Dates[i].Month)
        @Html.TextBoxFor(m => m.Dates[i].Month, new { @class = "month" })
        @Html.ValidationMessageFor(m => m.Dates[i].Month)
        @Html.LabelFor(m => m.Dates[i].Day)
        @Html.TextBoxFor(m => m.Dates[i].Day, new { @class = "day" })
        @Html.ValidationMessageFor(m => m.Dates[i].Day)
        @Html.HiddenFor(m => m.Dates[i].Date, new { @class = "date" })
        @Html.ValidationMessageFor(m => m.Dates[i].Date, null, new { @class = "validation" })
    </div>
}

and then include the following scripts

$('.day, .month, .year').change(function () {
    var container = $(this).closest('.date-container');
    var day = Number(container.find('.day').val());
    var month = Number(container.find('.month').val());
    var year = Number(container.find('.year').val());
    if (isNaN(day) || isNaN(month) || isNaN(year) || day === 0 || month === 0 || year === 0) {
        container.find('.date').val('');
        return;
    }
    var date = new Date(year, month - 1, day);
    var isValid = date.getDate() === day && date.getMonth() === month - 1 && date.getFullYear() === year;
    if (isValid) {
        container.find('.date').val(year + '-' + month + '-' + day);
        container.find('.validation').text('').addClass('field-validation-valid').removeClass('field-validation-error');
    } else {
        container.find('.date').val('');
        container.find('.validation').text('The values for the date are not valid').addClass('field-validation-error').removeClass('field-validation-valid');
    }
});

$('form').submit(function () {
    $.each($('.date'), function () {
        if (!$(this).val()) {
            return false;
        }
    });
})

Upvotes: 1

Lukasz Mk
Lukasz Mk

Reputation: 7350

As far I know You must create your own custom validator.

Look google for more information about ValidationAttribute, IClientValidatable and - in your case - also IValidatableObject.

Few examples:


Look also this question


Other way - you can consider using date-picker control instant of three fields. Date-picker gives you easy way to date validation plus few interesting features.

Try this one: eternicode/bootstrap-datepicker (also available via bower).

Upvotes: 0

Related Questions