1. ホーム
  2. javascript

[解決済み] AngularJSで双方向のフィルタリングを行うには?

2022-08-11 06:18:43

質問

AngularJSでできる面白いことの1つは、特定のデータバインディング式にフィルタを適用することです。これは、例えばモデルのプロパティに文化特有の通貨や日付のフォーマットを適用するのに便利な方法です。また、スコープ上に計算されたプロパティを持つのも良いことです。問題は、これらの機能はどちらも双方向のデータバインディングシナリオで動作しないことです。これは、他の優れたライブラリの目立った欠落であるように思えますが、私は何かを見逃しているのでしょうか?

KnockoutJS では、読み取り/書き込み可能な計算プロパティを作成することができ、プロパティの値を取得するために呼び出される関数と、プロパティが設定されたときに呼び出される関数のペアを指定することが可能でした。これにより、例えばカルチャーを考慮した入力、つまりユーザーに "$1.24" と入力させ、それを ViewModel の float に解析し、ViewModel の変更が入力に反映されるように実装することができました。

これと似たようなものを見つけることができたのは $scope.$watch(propertyName, functionOrNGExpression); のプロパティが指定されたときに呼び出される関数を用意することです。 $scope のプロパティが変更されたときに呼び出される関数を持つことができます。しかし、これは例えばカルチャを考慮した入力の問題を解決するものではありません。を変更しようとしたときの問題に注目してください。 $watched プロパティ内で $watch メソッド自体の中にあります。

$scope.$watch("property", function (newValue, oldValue) {
    $scope.outputMessage = "oldValue: " + oldValue + " newValue: " + newValue;
    $scope.property = Globalize.parseFloat(newValue);
});

( http://jsfiddle.net/gyZH8/2/ )

ユーザーが入力を開始すると、input 要素は非常に混乱します。解析されていない値用と解析された値用の2つのプロパティに分割することで改善しました。

$scope.visibleProperty= 0.0;
$scope.hiddenProperty = 0.0;
$scope.$watch("visibleProperty", function (newValue, oldValue) {
    $scope.outputMessage = "oldValue: " + oldValue + " newValue: " + newValue;
    $scope.hiddenProperty = Globalize.parseFloat(newValue);
});

( http://jsfiddle.net/XkPNv/1/ )

これは最初のバージョンより改善されましたが、少し冗長になり、また、まだ parsedValue プロパティが変更されることに注意してください (2 番目の入力で何かを入力すると、その入力によって parsedValue を直接変更します。一番上の入力は更新されないことに注意してください)。これは、コントローラのアクションやデータサービスからのデータの読み込みによって発生する可能性があります。

AngularJSを使用してこのシナリオを実装するための簡単な方法はありますか?ドキュメントにある機能を見逃しているのでしょうか?

どのように解決するのですか?

これには非常にエレガントな解決策があることがわかりましたが、あまり文書化されていません。

表示するためのモデルの値のフォーマットは | 演算子と、角のある formatter . フォーマッタのリストだけでなく、パーサーのリストも持っている ngModel があることがわかります。

1. 使用方法 ng-model を使用して、双方向のデータバインディングを作成します。

<input type="text" ng-model="foo.bar"></input>

2. 同じ要素に適用されるディレクティブをangularモジュールに作成し、そのディレクティブは ngModel コントローラ

module.directive('lowercase', function() {
    return {
        restrict: 'A',
        require: 'ngModel',
        link: function(scope, element, attr, ngModel) {
            ...
        }
    };
});

3. の中で link メソッド内で、カスタムコンバータを ngModel コントローラに追加します。

function fromUser(text) {
    return (text || '').toUpperCase();
}

function toUser(text) {
    return (text || '').toLowerCase();
}
ngModel.$parsers.push(fromUser);
ngModel.$formatters.push(toUser);

4. 新しいディレクティブを、すでに存在する ngModel

<input type="text" lowercase ng-model="foo.bar"></input>

ここでは の動作例です。 の中でテキストを小文字に変換しています。 input で小文字に変換し、モデルで大文字に戻しています。

モデルコントローラの API ドキュメント にも、簡単な説明とその他の利用可能なメソッドの概要があります。