JSFiddle - React, Tailwind, and code Playground

HTML

<link rel="stylesheet" href="http://netdna.bootstrapcdn.com/bootstrap/3.1.1/css/bootstrap.min.css">
<p>In this example, the input is validated using Angular's ng-pattern, with a Regex that embodies the signature of a U.S. Zip-Code or Zip+4. Each time validity changes, the handler will fire, and you'll see an alert announcing the change.</p>

<p>The property representing the validity of the input is identified as `$valid` and is stored on the ng-model controller. We can inject that controller into our directive using the `require` property, then reference it on $scope and $watch it.</p>

<p>Note that this works equally well if you provide names for your form and the input, and watch it as "formName.inputName.$valid". However, your directive will thereafter be imperatively bound to that specific form-name and input-name.</p>

<div class="container" ng-app="ModelsDemo">
    <form ng-controller="mainCtrl">
        <label>Zip-Code <input filter-test="" ng-model="zipCode" ng-pattern="regexes.zip" /></label>
    </form>    
</div>

CSS

input.ng-valid.ng-dirty,
select.ng-valid.ng-dirty {
  border-color: #78FA89;
}

form input.ng-invalid.ng-dirty,
form select.ng-invalid.ng-dirty {
  border-color: #FA787E;
}
form td.ng-invalid.ng-dirty {
  border: 2px solid #FA787E;
}

input:focus:required:invalid:focus, textarea:focus:required:invalid:focus, select:focus:required:invalid:focus {
  border-color: #e9322d;
  -webkit-box-shadow: 0 0 6px #f8b9b7;
  -moz-box-shadow: 0 0 6px #f8b9b7;
  box-shadow: 0 0 6px #f8b9b7;
}

JavaScript

angular.module('ModelsDemo',[])

angular.module('ModelsDemo').controller('mainCtrl', function($scope) {
  $scope.zipCode=10009;
    
  $scope.regexes = {
    zip: /(^\d{5}$)|(^\d{5}-\d{4}$)/,
    /* Zip or Zip+4 */
    numsOnly: /^\d+$/
    }
  $scope.noteChanges = function(newVal, oldVal) {
      if (newVal !== oldVal) {   
          alert('property changed from: ' + oldVal + ", to: " + newVal)
      }
  }
      
  })

angular.module('ModelsDemo').directive('filterTest', function() {
    return {
        restrict: "A",
        require: '',
        link: function(scope, element, attrs, controller) {
            console.log(controller.$valid);
            scope.inputCtrl = controller;
            scope.$watch('inputCtrl.$valid', scope.noteChanges)
        
        }
    
    }
})