Take the 2-minute tour ×
Stack Overflow is a question and answer site for professional and enthusiast programmers. It's 100% free, no registration required.

Aloha. I have two fields for time input, start + end. I've created custom validations to check if field is blank, valid time, and start is before end time. Works except for the following:

  • edit both times to be 7:45 and 7:50 respectively, no errors;
  • edit end time to be before the start time, from 7:50 to 7:44, the validation does its job, i.e. $error.validAfter = true;
  • ignore end time field and edit start time to be after the end time, from 7:45 to 7:47, ($error.validBefore error = true);
  • edit start time to be before end time, from 7:47 to 7:43 - $error.validBefore = false;

At this point, $error.validAfter is still true for end time. Is there a way to update this after the validation for start time, fourth bullet, has been confirmed?

HTML:

<div data-ng-app="scheduleApp">
<h2>{{ "Schedule App" }}</h2>
<div class="time" data-ng-form="formtime">
    <div class="form-row">
        <span class="label">Start time:</span>
        <span class="field">
            <input type="text" name="startTime" ng-model="startTime" is-from placeholder="e.g. 7:50" required validatetime="{{ endTime }}" />
            <span class="error" ng-class="{required: formtime.startTime.$error.required, invalid: formtime.startTime.$error.validTime}">enter a valid time, <i>hh:mm</i></span>
            <span class="error" ng-show="formtime.startTime.$error.validBefore" ng-class="{invalid: formtime.startTime.$error.validBefore && !formtime.startTime.$error.validTime}">start time must be before the end time</span>
        </span>
        <span>{{ formtime.startTime.$error }}</span>
    </div>
    <div class="form-row">
        <span class="label">End time:</span>
        <span class="field">
            <input type="text" name="endTime" ng-model="endTime" placeholder="e.g. 7:55" required validatetime="{{ startTime }}" />
            <span class="error" ng-class="{required: formtime.endTime.$error.required, invalid: formtime.endTime.$error.validTime}">enter a valid time, <i>hh:mm</i></span>
            <span class="error" ng-show="formtime.endTime.$error.validAfter" ng-class="{invalid: formtime.endTime.$error.validAfter && !formtime.endTime.$error.validTime}">end time must be after the start time</span>
        </span>
        <span>{{ formtime.endTime.$error }}</span>
    </div>
</div>

Javascript:

var app = angular.module("scheduleApp", []);

function PMhour(hour) {
    var pmHours = [1,2,3,4,5,6];

    return pmHours.indexOf(hour) >= 0 ? (hour + 12) : hour;
}

app.directive("validatetime", function() {
    return {
        restrict:   "A"
        , require:  "ngModel"
        , link:
            function($scope, elem, attrs, ctrl) {
                var validTime       = false;
                var validCompare    = false;
                var isFrom          = attrs.isFrom == null ? false : true;
                var otherTime;

                attrs.$observe("validatetime", function(otherTimeVal) {
                    otherTime   = otherTimeVal;
                });

                ctrl.$parsers.unshift   (isValidTime, isValidTimeCompare);
                ctrl.$formatters.unshift(isValidTime, isValidTimeCompare);

                function isValidTime(value) {
                    var regex   = /^([0-9]|0[0-9]|1[0-9]|2[0-3]):[0-5][0-9]$/i;

                    validTime   = false;

                    if (value != null) {
                        if (value.length) {
                            validTime   = regex.test(value);
                        }
                    }

                    ctrl.$setValidity('validTime', validTime);

                    if (validTime) {
                        return value;
                    }
                }

                function isValidTimeCompare(value) {
                    var tmpFrom;
                    var tmpTo;

                    if (otherTime) {
                        validCompare    = (otherTime.length == 0);
                    }
                    else {
                        validCompare    = true;
                    }

                    if (validTime) {
                        if (otherTime.length) {
                            if (isFrom) {
                                tmpTo   = new Date(2000, 0, 1, PMhour(parseInt(otherTime.split(":")[0])), parseInt(otherTime.split(":")[1]));
                                tmpFrom = new Date(2000, 0, 1, PMhour(parseInt(value.split(":")[0]))    , parseInt(value.split(":")[1]));
                            }
                            else {
                                tmpFrom = new Date(2000, 0, 1, PMhour(parseInt(otherTime.split(":")[0])), parseInt(otherTime.split(":")[1]));
                                tmpTo   = new Date(2000, 0, 1, PMhour(parseInt(value.split(":")[0]))    , parseInt(value.split(":")[1]));
                            }

                            validCompare = (tmpFrom < tmpTo);
                        }
                    }

                    if (isFrom) {
                        ctrl.$setValidity("validBefore", validCompare); // from is before the other time
                    }
                    else {
                        ctrl.$setValidity("validAfter", validCompare);      // to is after the other time
                    }

                    return value;
                };
            }
    }
});

Plunker here: http://plnkr.co/edit/Innbv6lCYewefSgKhvGA?p=info
Sorry, I'm new to the plunker concept. Let me know if you cannot see the code. Mahalo for your assistance.

share|improve this question

1 Answer 1

I think you're just overly complicating things. Just keep track of one variable, isValid, which you update every time either value changes. Simply compare the beginning and end as dates like you're doing and you should be golden.

Just a note - your code looks pretty complicated - you probably don't need more than just a $watch on each time field, in which you execute a checkValidity() function using both field values'. Let me know if that doesn't make sense.

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.