25

$formatter を含むいくつかのカスタム検証コードがあります。(正確を期すために通貨をペンスで保存しますが、ポンド.ペンスで表示します。)

ユーザーが入力に '10' を入力した場合 (これは有効な値です)、次のフィールドに移動した後も入力には '10' が表示されたままになります。

一貫性を保つために 10.00 を表示したいと思います。

モデルが値を 1000 に変更した場合、フォーマッタはフィールドに「10.00」を表示します。

フォーマッタを field.blur() で実行したいと思います (入力が有効である限り)。

私の問題は、モデル値を 10 から 10 に変更すると、当然のことながら変更がないため、フィールドが再レンダリングされないことです。

コード:

var CURRENCY_REGEXP = /^\-?\d+(\.?\d?\d?)?$/;
app.directive('currency', function() {
  return {
    require: 'ngModel',
    link: function(scope, elm, attrs, ctrl) {
      ctrl.$parsers.unshift(function(viewValue) {
        if (CURRENCY_REGEXP.test(viewValue)) {
          // it is valid
          ctrl.$setValidity('currency', true);
          console.log("valid");
          return viewValue * 100;
        } else if (viewValue === '') {
          return 0;
        } else {
          // it is invalid, return undefined (no model update)
          ctrl.$setValidity('currency', false);
          console.log("invalid");
          return undefined;
        }
      });
      ctrl.$formatters.push(function(modelValue) {
         if (modelValue === 0) { // we're using integer pence, so this is safe
             return '';
         }
         return (modelValue / 100).toFixed(2); 
      });
    }
  };
});

PS これは、Angular の組み込みの「通貨」とは何の関係もありません。


更新: Andy の回答に従って、「renderOnBlur」ディレクティブを追加しました。呼び出されますが、render メソッドを呼び出しても入力は再レンダリングされません。つまり、'10' は、必要に応じて '10.00' に変更するのではなく、'10' のままです。

(これらのフィールドでモデル値が変更されると、小数点以下 2 桁で正しくレンダリングされます。)

Andy が言及しているページhttp://docs.angularjs.org/api/ng.directive:ngModel.NgModelControllerには、自分で実装する必要があると書かれてい$renderます。モデル値が変更されたときに入力がすでに正しくレンダリングされているため、これは奇妙に思えます。

app.directive('renderOnBlur', function() {
    return {
        require: 'ngModel',
        restrict: 'A',
        link: function(scope, elm, attrs, ctrl) {
            elm.bind('blur', function() {
                console.log('rendering ctrl', ctrl);
                ctrl.$render();
            });
        }
    };  
});

PS私は何が何をするのか分かりrestrict: 'A',ません-それは最悪の真のカーゴカルトプログラミングです. パラメータrequire: 'ngModel',を入力する必要があるようです。ctrl


@Dan Doyen からの回答に触発されて、次のように書き直しました。

app.directive('renderOnBlur', function() {
    return {
        require: 'ngModel',
        restrict: 'A',
        link: function(scope, elm, attrs, ctrl) {
            elm.bind('blur', function() {
                var viewValue = ctrl.$modelValue;
                for (var i in ctrl.$formatters) {
                    viewValue = ctrl.$formatters[i](viewValue);
                }
                ctrl.$viewValue = viewValue;
                ctrl.$render();
            });
        }
    };  
});

これには、ダンの回答のようにフォーマッタ コードを繰り返すのではなく、任意の $formatter に対して汎用的であるという利点があります。

4

5 に答える 5

15

ただし、コントローラーの $modelValue は適切に更新されていますが、ぼかしイベントが角度の外で発生しているため、 $viewValue はそうではないようです。これはどう?

 elm.bind('blur', function() {
       ctrl.$viewValue = (ctrl.$modelValue / 100).toFixed(2);
       ctrl.$render();
 });
于 2012-07-11T17:47:19.940 に答える
3

少し改善: 値が有効でない場合は再フォーマットしないでください (私の場合、無効なテキストがぼかしでクリアされました。これは使いやすさに悪いと思います)。

また、Dark Falcon が言ったように、フォーマッターは逆方向に反復する必要があります。

最後に、少なくとも hasOwnProperty() をチェックせずに、for-in を使用して配列を反復処理しないでください (私にとっては、Array.find() をフォーマッタとして扱ったため、コードがクラッシュしました)。

// Reformat text on blur
elements.bind('blur', function() {
    if(!ngModel.$valid) {
        return;
    }
    var viewValue = ngModel.$modelValue;
    var formatters = ngModel.$formatters;
    for (var i = formatters.length - 1; i >= 0; --i) {
        viewValue = formatters[i](viewValue);
    }
    ngModel.$viewValue = viewValue;
    ngModel.$render();
});
于 2015-07-24T08:41:35.830 に答える
0

ぼかしに ctrl.$render を使用してみてください。

elm.bind('blur', function() { ctrl.$render() });

http://docs.angularjs.org/api/ng.directive:ngModel.NgModelControllerで参照してください。

于 2012-07-08T15:19:34.113 に答える
-1

10.00 === 10true

a=10.00

console.log(a)10

.00はjavascriptで何も意味しません。このため、10.00は10になります。

必要な形式を作成できるように、値を文字列にすることをお勧めします

于 2012-07-08T17:33:30.077 に答える