0

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

} });

4

2 に答える 2

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

そして、働くプランカー

于 2015-02-26T06:48:32.520 に答える
1

@doog abidesがすでに言ったことへの追加

$timeout interval を 0 として使用できます。その場合は同じように機能します

scope.textChanged = function() { 
    $timeout(function(){ 
      updateValue();
      scope.ngChange(); }, 0); // could be Zero
于 2015-02-26T07:21:28.207 に答える