14

私が達成しようとしているのは、入力フィールドに追加のインターフェイスを追加して、+ ボタンと - ボタンをクリックして数値を増減できるようにすることです。

(本質的には、input[type=number] フィールドが chrome で持っているものですが、これをクロス ブラウザーと互換性があり、すべてのブラウザーでプレゼンテーションを完全に制御できるようにしたいと考えています)。

ビュー内のコード:

<input data-ng-model="session.amountChosen" type="text" min="1" class="form-control input-small" data-number-input>

指令コード:

app.directive('numberInput', function() {
return {
    require: 'ngModel',
    scope: true,
    link: function(scope, elm, attrs, ctrl) {

        var currValue = parseInt(scope.$eval(attrs.ngModel)),
            minValue = attrs.min || 0,
            maxValue = attrs.max || Infinity,
            newValue;

        //puts a wrap around the input and adds + and - buttons
        elm.wrap('<div class="number-input-wrap"></div>').parent().append('<div class="number-input-controls"><a href="#" class="btn btn-xs btn-pluimen">+</a><a href="#" class="btn btn-xs btn-pluimen">-</a></div>');

        //finds the buttons ands binds a click event to them where the model increase/decrease should happen
        elm.parent().find('a').bind('click',function(e){

            if(this.text=='+' && currValue<maxValue) {
                newValue = currValue+1;    
            } else if (this.text=='-' && currValue>minValue) {
                newValue = currValue-1;    
            }

            scope.$apply(function(){
                scope.ngModel = newValue;
            });

            e.preventDefault();
        });


    }
  };

}))

これは、scope.$eval(attrs.ngModel) を介して現在のモデル値を取得できますが、新しい値の設定に失敗します。

編集後: これは現在動作するコードです (この問題の解決策を見たくない場合)

app.directive('numberInput', function() {
  return {
    require: 'ngModel',
    scope: true,
    link: function(scope, elm, attrs, ctrl) {

        var minValue = attrs.min || 0,
            maxValue = attrs.max || Infinity;

        elm.wrap('<div class="number-input-wrap"></div>').parent().append('<div class="number-input-controls"><a href="#" class="btn btn-xs btn-pluimen">+</a><a href="#" class="btn btn-xs btn-pluimen">-</a></div>');
        elm.parent().find('a').bind('click',function(e){

            var currValue = parseInt(scope.$eval(attrs.ngModel)),
                newValue = currValue;

            if(this.text=='+' && currValue<maxValue) {
                newValue = currValue+1;    
            } else if (this.text=='-' && currValue>minValue) {
                newValue = currValue-1;    
            }

            scope.$eval(attrs.ngModel + "=" + newValue);
            scope.$apply();            

            e.preventDefault();
        });
    }
  };
})
4

3 に答える 3

32

$eval() の代わりにngModelControllerメソッドを使用して、ng-model プロパティの値を取得および設定する必要があります。

$eval は値を数値に変換するため、数値で属性を評価する場合は parseInt() は必要ありません。変数 minValue および maxValue を設定するには、$eval を使用する必要があります。

ディレクティブで子スコープを作成する必要はありません。

ngModelController メソッド (特に $render()) がビューを自動的に更新するため、$apply() は必要ありません。ただし、@Harijs が以下のコメントで指摘しているように、アプリの他の部分も更新する必要がある場合は $apply() が必要です。

app.directive('numberInput', function ($parse) {
    return {
        require: 'ngModel',
        link: function (scope, elm, attrs, ctrl) {
            var minValue = scope.$eval(attrs.min) || 0,
                maxValue = scope.$eval(attrs.max) || Infinity;
            elm.wrap('<div class="number-input-wrap"></div>').parent()
                .append('<div class="number-input-controls"><a href="#" class="btn btn-xs btn-pluimen">+</a><a href="#" class="btn btn-xs btn-pluimen">-</a></div>');
            elm.parent().find('a').bind('click', function (e) {
                var currValue = ctrl.$modelValue,
                    newValue;
                if (this.text === '+' && currValue < maxValue) {
                    newValue = currValue + 1;
                } else if (this.text === '-' && currValue > minValue) {
                    newValue = currValue - 1;
                }
                ctrl.$setViewValue(newValue);
                ctrl.$render();
                e.preventDefault();
                scope.$apply(); // needed if other parts of the app need to be updated
            });
        }
    };
});

fiddle

于 2013-08-16T01:14:51.043 に答える
4

scope.ngModel変数を置き換えるのではなく、その変数の背後にある値を置き換えます。リンク関数の最初の行の値を読んだときに、すでにそれを行っています。

 currValue = parseInt(scope.$eval(attrs.ngModel))
 //                         ^^^^^^^^^^^^^^^^^^^^

のような単純な値の場合myProperty、スコープでそれを使用できます。

 scope[attr.ngModel] = newValue

ただし、 のような式の値がある場合、これは機能しませんcontainer.myProperty。その場合 (そして、これはより一般的な型であり、目指すべきものです)、次のように、スコープに設定されている値を評価する必要があります。

scope.$eval(attrs.ngModel + "=" + newValue)

JavaScript でペンダントを使用しているため、この$eval部分が少し見にくいことは認めざるを得ませんが、問題はありません。evalString 値を設定する場合は、この方法では機能しない可能性があることに注意してください。次に、それらの値をエスケープする必要があります。

それが役立つことを願っています;)

于 2013-08-15T09:55:37.317 に答える
3
.directive('numberInput', function ($parse) {
   return {
      require: 'ngModel',
      link: function (scope, elm, attrs){ 
        elm.bind("click", function() {
          var model = $parse(attrs.ngModel);
          var modelSetter = model.assign;
          scope.$apply(function() {
               modelSetter(scope, model);
          });
     }
  }
})
于 2015-06-03T07:49:23.287 に答える