title: AngularJS how do I watch $viewValue instead of ngModel?
body: <p>I am using debounce on an input:</p>
  
  <pre><code>&lt;input type="text"
       ng-model="model.qty"
       ng-model-options="{ debounce : 1000 }"
       min="{{model.min}}" max="{{model.max}}" step="1"
       qty-input validate-model-setting&gt;
  </code></pre>
  
  <p>I have a directive that handles the disabling of an increment button and a decrement button for this input:</p>
  
  <pre><code>app.directive('qtyInput', function() {
      return {
          restrict: 'A',
          require: '?ngModel',
          link: function(scope, element, attrs, ngModelCtrl) {
              scope.$watch(attrs.ngModel, function(n, o) {
                  var val = parseInt(n);
                  if(!isNaN(val)) {
                      if(val + 1 &gt; model.max) {
                          scope.quantityIncDisabled = true;
                      } else {
                          scope.quantityIncDisabled = false;
                      }
                      if(val - 1 &lt; model.min) {
                          scope.quantityDecDisabled = true;
                      } else {
                          scope.quantityDecDisabled = false;
                      }
                  }
              });
          }
      }
  });
  </code></pre>
  
  <p>The problem is, the watch on this directive is looking at the model.  I need it to look at the <code>$viewValue</code> instead.  This is because, due to debounce, there is a race condition between typing in the input and using the increment/decrement buttons.  For example, you can keep on clicking the decrement button over and over for exactly 1 second after the input has reached 1 (the min), and only then, after the debounce finishes, will the decrement button become disabled.  Instead, I want the button to be disabled immediately when the input reaches 1, not after waiting the full debounce second.  My best guess is that this means putting a <code>$watch</code> on the <code>$viewValue</code>, but I don't know how to get to it in the directive.</p>
  
  <p>For your reference, the buttons themselves avoid the race condition by changing the input's value and then triggering the input, which makes the debounce work fluidly with both typing in the input and using the buttons.  </p>
  
  <pre><code>   link: function(scope, element, attrs) {
          element.bind('click', function() {
              $timeout(function() {
                  var input = element.parent().find('input');
                  var changingTo = parseInt(input[0].value) + parseInt(scope.inc);
                  if(scope.inc &lt; 0 || isNaN(changingTo)) {
                      var min = parseInt(input[0].min);
                      if(isNaN(changingTo)) {
                          changingTo = min;
                      } else if(changingTo &lt; min) {
                          return;
                      }
                  } else {
                      var max = parseInt(input[0].max);
                      if(changingTo &gt; max) {
                          return;
                      }
                  }
                  input[0].value = String(changingTo);
                  input.trigger('input');
              });
          });
      }
  </code></pre>