AngularJS指令不会触发On-Change回调

时间:2015-02-26 05:10:46

标签: javascript angularjs angularjs-directive angularjs-ng-change

我已经创建了一个用于CSS样式的数字步进器,但是当您手动输入ng-change时,我遇到了触发<div class="stepper-container"> <input type="text" ng-model="ngModel"> <button class="stepper-up fa fa-chevron-up" ng-click="increment()"></button> <button class="stepper-down fa fa-chevron-down" ng-click="decrement()"></button> </div> 的问题。

我在plunker上创建了一个日志,以说明何时触发回调。正如您在播放时所看到的,当您单击步进箭头时它可以正常工作,但是当您直接在框中输入时它不会正常工作。

当前代码示例: Plunker

HTML:

var app = angular.module('plunker', []);

app.controller('MainCtrl', function($scope) {
  $scope.myModel = null;
  $scope.log = [];

  $scope.someMethod = function () {
    $scope.log.push('Change event on ' + $scope.myModel);
  }
});

app.directive('numericStepper', function () {
  return {
    restrict: 'EA',
    require: 'ngModel',
    scope: {
      ngModel: '='
    },
    replace: true,
    templateUrl: 'numeric-stepper.html',
    link: function (scope, element, attrs, ngModelCtrl) {
      console.log('NumericStepper::link', ngModelCtrl.$viewValue);

      var sizingUnit = null;
      var css3Lengths = [
        // Percentage
        '%',
        // Font Relative
        'em', 'ex', 'ch', 'rem',
        // Viewport Relative
        'vw', 'vh', 'vmin', 'vmax',
        // Absolute
        'cm', 'mm', 'in', 'px', 'pt', 'pc'
      ];

      scope.$watch(function () {
        return ngModelCtrl.$modelValue;
      }, function (newValue, oldValue) {
        updateValue();
      });

      ngModelCtrl.$formatters.unshift(function (value) {
        value = isNaN(parseInt(value)) ? 0 : value;
        return value;
      });

      scope.increment = function () {
        updateValue(1)
      };

      scope.decrement = function () {
        updateValue(-1);
      };

      function updateValue(amount) {
        var matches = ngModelCtrl.$viewValue.toString().split(/(-?\d+)/);
        var value = (parseInt(matches[1]) || 0) + (amount || 0);
        sizingUnit = matches[2].trim();

        ngModelCtrl.$setViewValue(value + sizingUnit);
        sanityCheck();
      }

      function sanityCheck() {
        var validity = css3Lengths.indexOf(sizingUnit) != -1;
        ngModelCtrl.$setValidity('invalidUnits', validity);
      }
    }

JavaScript的:

{{1}}

} });

2 个答案:

答案 0 :(得分:2)

更改模板文本框以包含针对ngChange的隔离范围调用。在该函数中,使用超时允许模型更新/摘要在调用父控制器更改函数之前发生...

因此,请更改模板文本框:

<input type="text" ng-model="ngModel" ng-change="textChanged()">

然后改变你的指令:

// $timeout works better here than watch
app.directive('numericStepper', function ($timeout) { 

  return {
    restrict: 'EA',
    require: 'ngModel',
    scope: {
      ngModel: '=',
      ngChange: '&' // add me!
    },
    replace: true,
    templateUrl: 'numeric-stepper.html',
    link: function (scope, element, attrs, ngModelCtrl) {
      console.log('NumericStepper::link', ngModelCtrl.$viewValue);

      var sizingUnit = null;
      var css3Lengths = [
        // Percentage
        '%',
        // Font Relative
        'em', 'ex', 'ch', 'rem',
        // Viewport Relative
        'vw', 'vh', 'vmin', 'vmax',
        // Absolute
        'cm', 'mm', 'in', 'px', 'pt', 'pc'
      ];
      /********** DONT NEED THIS
      // scope.$watch(function () {
      //   return ngModelCtrl.$modelValue;
      // }, function (newValue, oldValue) {
      //   updateValue();
      // });
      ******************/

      // Add this function
      scope.textChanged = function() { 
        $timeout(function(){ 
          updateValue();
          scope.ngChange(); }, 500); // could be lower
      }
      ngModelCtrl.$formatters.unshift(function (value) {
        value = isNaN(parseInt(value)) ? 0 : value;
        return value;
      });

      scope.increment = function () {
        updateValue(1)
      };

      scope.decrement = function () {
        updateValue(-1);
      };

      function updateValue(amount) {
        var matches = ngModelCtrl.$viewValue.toString().split(/(-?\d+)/);
        var value = (parseInt(matches[1]) || 0) + (amount || 0);
        sizingUnit = matches[2].trim();

        ngModelCtrl.$setViewValue(value + sizingUnit);
        sanityCheck();
      }

      function sanityCheck() {
        var validity = css3Lengths.indexOf(sizingUnit) != -1;
        ngModelCtrl.$setValidity('invalidUnits', validity);
      }
    }
  }
});

工作plunker

答案 1 :(得分:1)

插入@doog已经说过的内容

你可以使用$ timeout interval作为0,它的工作方式与

相同
scope.textChanged = function() { 
    $timeout(function(){ 
      updateValue();
      scope.ngChange(); }, 0); // could be Zero