web-dev-qa-db-ja.com

AngularJSで双方向フィルタリングを行う方法は?

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を使用してこのシナリオを実装する簡単な方法はありますか?ドキュメントにいくつかの機能がありませんか?

123
Jeremy Bell

これには非常に洗練された解決策がありますが、十分に文書化されていません。

表示用のモデル値の書式設定は、|演算子とangular formatterで処理できます。フォーマッタのリストだけでなく、パーサーのリストも。

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ドキュメント には、利用可能な他のメソッドの簡単な説明と概要も記載されています。

230
phaas