[AngularJS] 6. カスタムフィルタ≪改訂≫

---
[目次](http://qiita.com/Koizumi-Greenwich/items/3e327e3331b2f728797e)
≪前の記事 5.[イベント処理≪改訂≫](http://qiita.com/Koizumi-Greenwich/items/12a65385177ebbb488d5)
≫次の記事 7.[ディレクティブ](http://qiita.com/Koizumi-Greenwich/items/287d36dfeb70333e00a4)

---
*【改訂】グローバル変数を使用しない記述法に改訂しました。*


#フィルタ
*フィルタ* は出力時に文字列を加工するための機能です。テンプレートの `{{ ... }}` や ng-bind、ng-bind-html ディレクティブ内で使用します。（[1. 初めの一歩](http://qiita.com/Koizumi-Greenwich/items/5f1799589eb335c6d68e#---タグ)も参照）

```text:フィルタ使用例
{{price | number}} 円
```

上記の例では、 **price** の値をAngularJS標準の **number**フィルタで加工しています。具体的には3桁ごとに「,(カンマ)」が入ります。

AngularJSには[標準でいくつかのフィルタ](http://js.studio-kingdom.com/angularjs/ng_filter)が用意されていますが、数も種類も少ないため多くの場合独自に作る必要が生じます。このように独自のフィルタを作成する仕組みが **カスタムフィルタ** です。

#フィルタの定義
カスタムフィルタを定義するには、モジュールオブジェクトの **filter** メソッドを使用します。

```text:フィルタ定義
モジュールオブジェクト.filter(フィルタ名, function(依存サービス, ...) {
	return function(仮引数) {    ← フィルタの処理を行う関数オブジェクト を返す
		〜出力値の加工処理〜
		
		return 加工済の値;
	}
});
```

**filter**メソッドの第1引数には、定義するフィルタ名を渡します。
第2引数には *フィルタの処理を行う関数オブジェクト* を返すコールバック関数を渡します。

コールバック関数の内部では、フィルタ処理関数を定義して、その関数オブジェクトを返すようにします。
また、コールバック関数でサービスを利用したい（依存サービス）場合は、そのオブジェクトを引数で渡しておきます。

フィルタ処理関数では引数を1つ受け取ります。この引数に **フィルタ前の出力値**が渡されます。フィルタ関数の内部ではこの仮引数で出力値を参照し、加工を行います。
そして加工済の値を返すようにします。

##フィルタ定義の例
```js:フィルタ定義の例(1)
module.filter('nl2br', function($sce) {
    return function(input) {
        if (input) {
            var replaced = input.replace(/(\r\n|\n|\r)/g, '<br>$1')
            return $sce.trustAsHtml(replaced);
        }
        return input;
    }
});
```

この例では、文字列の改行コードの前に `<br>`タグを挿入するフィルタ「nl2br」を定義しています。

変数`module`は、あらかじめ生成したモジュールオブジェクトです。

コールバック関数の引数には SCEサービスのオブジェクト `$sce` を渡しています。出力時にHTMLタグがエスケープされてしまうのを避けるために `$sce.trustAsHtml()` メソッドが必要になるからです。
このようにフィルタ処理内で依存するサービスオブジェクトを、コールバック関数の引数に渡しておきます。

フィルタ処理関数では、仮引数`input`で出力値（加工前）を受け取っています。そして改行コードの前に`<br>`タグを挿入する置換処理を行い、置換後の値を返すようにしています。

```js:フィルタ定義の例(2)
module.filter('yenNumber', function($filter) {
    return function(input) {
        if (input) {
            var numfilter = $filter('number');
            return numfilter(input) + '円';
        }
        return input;
    }
});
```

この例は、数字を3桁区切りにしたうえで、末尾に「円」を付けるフィルタ「yenNumber」を定義しています。

数字を3桁区切りにするには、AngularJS標準の **number** フィルタを利用します。このようにAngularJS標準のフィルタを利用する場合は、コールバック関数に `$filter`オブジェクトを渡します。

フィルタ処理ではまず、仮引数`input`で出力値（加工前）を受け取ります。
AngularJS標準のフィルタ関数は、`$filter(フィルタ名)` とすることで取得できます。ここでは `$filter('number')` で **number**フィルタ関数を取得しています。
そして、 **number**フィルタで出力値を加工し、末尾に「円」を付加した値を返しています。

#サンプルコード
```html:sample06.html
<!DOCTYPE html>
<meta charset="UTF-8">
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.15/angular.min.js"></script>
<script>
/**
 * アプリケーション モジュール オブジェクトの定義
 */
(function() {
    var module = angular.module("sampleModule", []);
})();
    
/**
 * フィルタの定義
 */
(function(module) {
    /**
     * nl2brフィルタ
     */
    module.filter('nl2br', function($sce) {
        return function(input) {
            if (input) {
                var replaced = input.replace(/(\r\n|\n|\r)/g, '<br>$1')
                return $sce.trustAsHtml(replaced);
            }
            return input;
        }
    });
    
    /**
     * yenNumberフィルタ
     */
    module.filter('yenNumber', function($filter) {
        return function(input) {
            if (input) {
                var numfilter = $filter('number');
                return numfilter(input) + '円';
            }
            return input;
        }
    });
    
    return module;
})(angular.module("sampleModule"));

/**
 * コントローラの定義
 */
(function(module) {
    /**
     * SampleController
     */
    module.controller("sampleController", function($scope, $sce, $timeout){
        $scope.message = "このメッセージは\n改行されて表示されていますか？";
        $scope.price   = 1234567;
    });
})(angular.module("sampleModule"));
</script>

<!-- sampleModule テンプレート -->
<div ng-app="sampleModule">
    <!-- sampleController テンプレート -->
    <div ng-controller="sampleController" ng-cloak>
        <p ng-bind-html="message | nl2br"></p>
        <p>{{price | yenNumber}}</p>
    </div>
</div>
```

---
[目次](http://qiita.com/Koizumi-Greenwich/items/3e327e3331b2f728797e)
≪前の記事 5.[イベント処理≪改訂≫](http://qiita.com/Koizumi-Greenwich/items/12a65385177ebbb488d5)
≫次の記事 7.[ディレクティブ](http://qiita.com/Koizumi-Greenwich/items/287d36dfeb70333e00a4)

---