7

I have a custom validation directive that I use to ensure two dates are within a valid range. The directive works fine when a user changes the values, however it does not trigger when I load in a new lineItem model via AJAX.

The problem is that a user could enter invalid dates on the form and trigger the error, then load another lineItem. At this point, there is an error message on the form even though the data in the form is valid.

If I try the same thing with Angular's built in validation (like required), the validation triggers and disappears appropriately. So, what do I need to do to make my validation trigger the same way as Angular's?

(note: I'm using novalidate on the form attribute, and Angular v1.1.5)

DIRECTIVE

ngApp.directive("validateBefore", function () {
    return {
        require: 'ngModel',
        link: function (scope, element, attrs, ctrl) {
            ctrl.$parsers.unshift(function(value) {
                var before = scope.$eval(attrs.validateBefore);
                if(value <= before || !before) {
                    ctrl.$setValidity("validateBefore", true);
                    return value;
                } else {
                    ctrl.$setValidity("validateBefore", false);
                    return undefined;
                }
            });
        }
    }
});

TEMPLATE

<div class="date-group">
    <span class="date">
        <input type="text" class="input-medium" name="starts-at" ng-model="lineItem.startsAt" placeholder="From..." validate-before="lineItem.endsAt">  
    </span>

    <span class="date">
        <input type="text" class="input-medium" name="ends-at" ng-model="lineItem.endsAt" placeholder="To..." validate-after="lineItem.startsAt"> 
    </span>    
</div>

CONTROLLER

var lineItem = LineItem.get( { id: lineItemId }, function () {
    $scope.lineItem = lineItem;

    if($scope.lineItemForm) {
        $scope.lineItemForm.$setPristine();
    }
}

1 Answer 1

10

Ah-hah, I was only accounting for half of the equation. The $parsers fire when input is sent from the DOM to the model. I needed to add $formatters, which sends data from the model to the DOM.

After the $parsers, I added the following:

ctrl.$formatters.unshift(function(value) {
    var before = scope.$eval(attrs.validateBefore);
    ctrl.$setValidity("validateBefore", before ? value <= before : true);
    return value;
});

This causes validation to fire the moment the model is changed. It's discussed more here: http://docs.angularjs.org/guide/forms, and here http://docs.angularjs.org/api/ng.directive:ngModel.NgModelController#$formatters

Sign up to request clarification or add additional context in comments.

1 Comment

it works! @ovi, the form field is appended with the css class "ng-invalid", but not "ng-dirty", take a look for that.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.