Validate Time Entry with Javascript

I was cleaning up a web form that had a textbox for the user to enter a time value. The thing I don’t love about using a textbox to capture a time value is that there’s no validation. The user might enter a bad value and not realize it, and I’d rather let them know right away rather than displaying a message after they try to submit the form.

Surely there’s something we can do with javascript and regular expressions to create an intuitive experience for the user, right?

Format Checkin’ Regular Expression

The first thing we’re going to need is a regular expression that can be used to determine if an entry is valid or not. I decided to use a pair: one for standard time and one for military time.

function validateTime(time) {
    if (!time) {
        return false;
    }
    var military = /^\s*([01]?\d|2[0-3]):[0-5]\d\s*$/i;
    var standard = /^\s*(0?\d|1[0-2]):[0-5]\d(\s+(AM|PM))?\s*$/i;
    return time.match(military) || time.match(standard);
}

Make Red When Invalid

Now that we have a way to determine if an entry is valid, we need to decide how to give that feedback to the user. My first thought was to use the input control’s keyup event to check the value and make the text red if it doesn’t match.

<input type="text" class="warnIfInvalid" />
$(new function () {
    $('.warnIfInvalid').on('keyup', function () {
        $(this).css('color', 'black');
        if (!validateTime($(this).val())) {
            $(this).css('color', 'red');
        }
    });
});

Change to Default When Invalid

The color feedback is nice, but what if our field is a required value? If the user doesn’t enter anything, there is nothing to let them know they did something wrong. So, my second idea was to use the input control’s blur event to force a default value if the user enters a blank or invalid value.

<input type="text" class="required" value="12:00 AM" />
$(new function () {
    $('.required').on('blur', function () {
        if (!validateTime($(this).val())) {
            $(this).val('12:00 AM');
        }
    });
});

Do Both!

I didn’t like simply changing the user’s value to a default value without letting them know that I’m about to do that. For example, my regular expression won’t match a standard time that doesn’t have a space between the minutes and AM/PM. We can combine both techniques described above to give the user feedback as they type but change their bad input to a default if they enter something invalid. (Note that I manually trigger the keyup event after changing the invalid value to my default value.)

<input type="text" class="required warnIfInvalid" value="12:00 AM" />
$(new function () {
    $('.required').on('blur', function () {
        if (!validateTime($(this).val())) {
            $(this).val('12:00 AM');
            $(this).keyup();
        }
    });
    $('.warnIfInvalid').on('keyup', function () {
        $(this).css('color', 'black');
        if (!validateTime($(this).val())) {
            $(this).css('color', 'red');
        }
    });
});

Live example can be found here: http://jsfiddle.net/adamprescott/Q9b6d/

Advertisement

Real-time Validation with Knockout

Knockout gives you a slick way to do real-time validation on your data with its built-in extenders. At first glance, it may not seem like an entirely intuitive process, but it’s actually pretty clever. When you use an extender, you’re extending the property to have additional sub-properties and behaviors. Makes sense, right?

Let’s look at a simple example: validating a date value.

We begin by creating a simple view model and UI.

var viewModel = function () {
    var self = this;
    this.dateValue = ko.observable();
};
ko.applyBindings(new viewModel());
<div>
    <input data-bind="value: dateValue" />
</div>

Now we can create our extender. We introduce a new hasError property that we’ll bind to the UI and use to show & hide validation messages. There’s a validate function that contains the validation logic. The validate method is called to perform the initial validation, and subscribe is called so that validate will be called when the value changes. Note that we also add valueUpdate: ‘afterkeydown’ to the input data-binding. This allows the validation to perform after each keystroke.

var viewModel = function () {
    var self = this;
    this.dateValue = ko.observable().extend({
        validDate: true
    });
};

ko.extenders.validDate = function (target) {
    target.hasError = ko.observable();

    function validate(value) {
        var invalid = isNaN(Date.parse(value));
        target.hasError(invalid);
    }

    validate(target());
    target.subscribe(validate);
    return target;
};

ko.applyBindings(new viewModel());
<div>
    <input data-bind="value: dateValue, valueUpdate: 'afterkeydown'" />
    <span data-bind="visible: dateValue.hasError">Invalid!</span>
</div>

That’s it for the hard stuff. All that’s left is to figure out what should be shown or hidden when the value is invalid or valid. I chose to show an alert icon and added some CSS to make the input box red.

.invalid input {
    border: 1px solid red;
}
.ui-icon {
    display: inline-block;
    vertical-align: middle;
}
<div data-bind="css: { invalid: dateValue.hasError }">
    <input data-bind="value: dateValue, valueUpdate: 'afterkeydown'" />
    <span class="ui-icon ui-icon-alert" title="Invalid value" data-bind="visible: dateValue.hasError"></span>
</div>

Check out this Fiddle for the working example.

%d bloggers like this: