javascript - AngularJS 指令不触发更改回调

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

我已经创建了一个与 CSS 样式一起使用的数字步进器,但在手动输入时让它触发 ng-change 时遇到问题。

我在 plunker 上创建了一个日志来说明回调何时被触发。正如您通过使用它所看到的,当您单击步进器箭头时它可以正常工作,但当您直接在框中键入时则不行。

当前代码示例: Plunker

HTML:

<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>

JavaScript:

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);
      }
    }

} });

最佳答案

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

因此更改您的模板文本框:

<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

关于javascript - AngularJS 指令不触发更改回调,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28734879/

相关文章:

angularjs - 为什么指令中的同一个值同时定义和未定义?

javascript - 使用 javascript 检查 obj 中的属性

javascript - 使用 "use strict"的函数形式。 angularjs 身份验证(使用 scala、play 框架)

javascript - 如何在for循环中添加DOM元素

css - event.preventDefault() 在 Android Ionic 中不起作用

java - Angularjs UI Bootstrap Popover 阻止输入提交

javascript - 有没有办法在 JavaScript 中对季节年份列表进行排序?

javascript - 使用工厂和 AngularJS 在 ngclick 方法内创建对象

angularjs - 如何使用 ng2-dnd 包从 json 而不是数组读取数据?

javascript - 将焦点设置在动态列表上(Angularjs 方式)