Ronald McDonald
Ronald McDonald

Reputation: 2911

Knockout validation only working on one of two date fields

I'm using knockout validation and the error class is being added to the EndDate field but not the StartDate field when it't empty. the class caused the field to have a red background. I can't see any difference in the two fields. Something similar is happening on my other pages also.

Upon further investigation i realize it's always the first date field on the page that doesn't work. If I comment out the first one then the second stops working.

**Edit: as a hack I added this above the first date field

<input id="StartDate2"  style="width: 140px;" type="hidden" data-bind="date: startDate">

and it works......but just feels really wrong.**

I have this at the beginning of my view model

        ko.validation.init({
            insertMessages: false,
            decorateElement: true,
            errorElementClass: "input-validation-error"
        });

from my model

    startDate:      KnockoutObservable<Date> = ko.observable(null).extend({ required: { message: "Please enter a start date." }, simpleDate: { message: "Please enter a valid start date." } });
    endDate:        KnockoutObservable<Date> = ko.observable(null).extend({ required: { message: "Please enter an end date." }, simpleDate: { message: "Please enter a valid end date." } });   

from the view

    <li>
        <label for="StartDate" class="required_label">Start Date</label>
        <input id="StartDate" style="width: 140px;" type="text" data-bind="date: startDate, valueUpdate: 'afterkeydown', class:{'input-validation-error':(!startDate.isValid() && showErrors())}" ">
    </li>
    <li>
        <label for="EndDate" class="required_label">End Date</label>
        <input id="EndDate" style="width: 140px;" type="text" data-bind="date: endDate">
    </li>

And here's our custome date binding handler

// mm/dd/yyyy format
ko.bindingHandlers.date = {
    init: (element, valueAccessor) => {
        $(element).mask("99/99/9999", { placeholder: "mm/dd/yyyy" });

        ko.utils.registerEventHandler(element, "change", () => {
            var value = valueAccessor();

            if (moment(element.value).isValid()) {
                value(element.value);
            } else {
                value(null);
            }
        });

        ko.validation.makeBindingHandlerValidatable("date");
    },
    update: (element, valueAccessor, allBindingsAccessor) => {
        var value = valueAccessor();
        var allBindings = allBindingsAccessor();
        var valueUnwrapped: any = ko.utils.unwrapObservable(value);
        var pattern = allBindings.format || "MM/DD/YYYY";
        var output = null;

        if (valueUnwrapped !== null && valueUnwrapped !== undefined && valueUnwrapped.length > 0) {
            output = moment(valueUnwrapped).format(pattern);
        }



        if ($(element).is("input") === true) {
            $(element).val(output);
        } else {
            $(element).text(output);
        }
    }
};

Upvotes: 0

Views: 358

Answers (1)

nemesv
nemesv

Reputation: 139758

You are making your date custom binding "validation compatible" only in its init function which will be only called when the binding is first used in the HTML. That is why the validation was only worked for the second input.

In order to fix this you have to move the ko.validation.makeBindingHandlerValidatable("date"); outside of your init function and have it after the whole binding handler declaration

ko.bindingHandlers.date = { 
   //...
}; 
ko.validation.makeBindingHandlerValidatable("date");

Upvotes: 1

Related Questions