[monaca]ui-routerでjson検索処理。

jsonで一括取得ではなく、その都度検索したい、って場合の処理。

# ベース

ui-routerでjsonを取得したリスト画面
[[monaca]ui-routerでjson取得処理。](https://qiita.com/miz21358/items/33eeb650df3b6e3ccf58)

# angular-animateの導入

詳細は、[[monaca]ui-routerで詳細スワイプ処理](https://qiita.com/drafts/b14675043893b94c2177)参照。

# animate.cssの導入

同上

# html

```index.html
<!DOCTYPE HTML>
<html>
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
  <meta http-equiv="Content-Security-Policy" content="default-src * data: gap: https://ssl.gstatic.com; style-src * 'unsafe-inline'; script-src * 'unsafe-inline' 'unsafe-eval'">
  <script src="components/loader.js"></script>
  <script src="script.js"></script>

  <link rel="stylesheet" href="components/loader.css">
  <link rel="stylesheet" href="css/style.css">
</head>
<body ng-app="MyApp">

	<ons-page>
        <!-- ツールバー -->
		<ons-toolbar>
			<div class="center">JSON検索</div>
		</ons-toolbar>
		
        <!-- 画面のメイン部分 -->
		<div>
			<ons-button ui-sref="search">JSON検索</ons-button>
		</div>
		
        <!-- 遷移読込部分 -->
		<div style="padding: 20px 10px;" ui-view></div>
		
        <!-- ローディング読込用ディレクティブ -->
		<my-loader></my-loader>

	</ons-page>
	
	<!-- リスト画面 -->
	<ons-template id="search.html">
		<div ng-controller="SearchController">
			<!-- 入力欄 -->
	        <ons-input ng-model="searchText" modifier="underbar" placeholder="国名等" float></ons-input>	
	        <!-- 検索ボタン -->
			<ons-button ng-click="searchCountry();">検索</ons-button>
			<div>{{message}}</div>
			<!--検索結果 -->
			<dl ng-repeat="(i, item) in list">
				<!-- 国名をタップしたら、詳細表示有無を反転させる -->
				<dt ng-click="shown[i] = !shown[i];">
					<!-- 詳細未表示時は右向きアイコン -->
		    		<ons-icon icon="fa-chevron-circle-right" ng-show="!shown[i]"></ons-icon>
					<!-- 詳細表示時は右向きアイコン -->
		    		<ons-icon icon="fa-chevron-circle-down" ng-show="shown[i]"></ons-icon>					    		
					{{item.country}}					
				</dt>
				<!-- 詳細情報は、詳細表示ON/OFFの切り替えでCSSを設定し、アニメーション表示する -->
				<dd ng-show="shown[i]">
					<ul>
						<li>英語名：{{item.english}}</li>
						<li>数: {{item.number}}</li>
						<li>三字: {{item.three}}</li>
						<li>二字: {{item.two}}</li>
						<li>場所: {{item.place}}</li>
						<li>各行政区分: {{item.division}}</li>
					</ul>
				</dd>
			</dl>
		</div>
	</ons-template>
	
    <!-- ローディング画面 -->
	<ons-template id="loader.html">
		<div ng-if="$root.isLoading" class="loader-parent"><div class="loader">Loading...</div></div>
	</ons-template>
</body>	
</html>

```

# json

```country.json
{
    "list": [
        {
            "country": "アイスランド", 
            "division": "ISO 3166-2:IS", 
            "english": "Iceland", 
            "number": "352", 
            "place": "北ヨーロッパ", 
            "three": "ISL", 
            "two": "IS"
        }, 
        {
            "country": "アイルランド", 
            "division": "ISO 3166-2:IE", 
            "english": "Ireland", 
            "number": "372", 
            "place": "西ヨーロッパ", 
            "three": "IRL", 
            "two": "IE"
        }, 
(略)
    ]
}
```

引用元）[国コード一覧CSV ISO 3166-1](https://qiita.com/tao_s/items/32b90a2751bfbdd585ea)

# javascript

```script.js
var myApp = angular.module('MyApp', ['onsen', 'ui.router', 'ngAnimate']);

// 遷移処理
myApp.config(['$stateProvider', '$urlRouterProvider', function($stateProvider, $urlRouterProvider) {

		$stateProvider
			.state('search', {
				url: '/search',
				templateUrl: 'search.html'
			})
			
	}]);

// 検索画面用コントローラ
myApp.controller('SearchController', ['$scope', '$state', '$rootScope', 'JsonCountryService', function($scope, $state, $rootScope, JsonCountryService) {
		
		$scope.searchCountry = function() {
			// まず、ローディングを回す
			$rootScope.isLoading = true;
			
			// Jsonデータ取得
			JsonCountryService.run($scope.searchText).then(
				function(resultList) {
					// 結果リストが取れたら、スコープに設定
					$scope.message = resultList.length + "件見つかりました。";
					$scope.list = resultList;
					
					// ローディング終了
					$rootScope.isLoading = false;
				}, function(response) {
					$scope.message = "検索結果がありませんでした。";
					$scope.list = null;
					
					// ローディング終了
					$rootScope.isLoading = false;
				}
			);
		}
	
	}]);

// ローディングタグ
myApp.directive('myLoader', function() {
		return {
			restrict : 'E',
			replace: true,
			templateUrl: "loader.html"
		};
	});	
	
	
// 画面遷移タイミング処理
myApp.run(['$rootScope', '$transitions', '$state', function($rootScope, $transitions, $state){
	$transitions.onSuccess({to:'*'}, function(trans){
		// ページ読み込み成功
		
		// ローディングフラグOFF
		$rootScope.isLoading = false;
	});
	
}]);
		

// JSON読込サービス
myApp.service('JsonCountryService', ['$q', '$timeout', '$http', '$filter', function($q, $timeout, $http, $filter){
     this.run = function (searchText) {
     	console.log("JsonCountryService searchText="+ searchText);
       	
		var deferred = $q.defer();
     	
		$timeout(function(){
			$http({
				method: 'GET',
				url: 'country.json'
			}).then(function successCallback(response) {	
				// 成功した場合			
				console.log("JsonCountryService success");
		
				var resultList;
				if (searchText && searchText.length > 0) {
					// 検索文字列が指定されている場合、リストの中から該当値のものだけ取得する
					// 検索範囲は絞りこまない
					// 完全一致ではなく、部分一致とする
					resultList = $filter("filter")(response.data.list, searchText, false);					
				}
				else {
					// 検索文字列が指定されていない場合、全データを返す
					resultList = response.data.list;
				}
				
				// 検索結果を返す
				deferred.resolve(resultList);

			}, function errorCallback(response) {
				// 失敗した場合
				var msg = "JsonCountryService json取得失敗: "+ response.status;
				
				console.error(msg);
				console.log("response.data"+ response.data);
				console.log("response.headers"+ response.headers);
				console.log("response.config"+ response.config);
				console.log("response.statusText"+ response.statusText);
				console.log("response.xhrStatus"+ response.xhrStatus);
				
				deferred.reject(msg);
			});
		});
		
		return deferred.promise;
    };

}]);
```

# css

```style.css
/* --------------------- 検索結果 ------------------------------- */

dt {
	font-size: large;
	font-weight: bold;
}
ul {
	padding: 0px;
}


/* --------------------- 詳細項目の表示/非表示アニメーション ------------------------------- */

dd.ng-hide-remove {
	animation: bounceInLeft 0.5s ease 0s 1 normal;
	-webkit-animation: bounceInLeft 0.5s ease 0s 1 normal;
	display: block!important;
}

dd.ng-hide-add {
	animation: bounceOutLeft 0.5s ease 0s 1 normal;
	-webkit-animation: bounceOutLeft 0.5s ease 0s 1 normal;
	display: block!important;
}

(略)
```

# 処理の流れ

1. ```JSON検索```ボタン押下
    2. ```state=search```に遷移
1. ```検索```ボタン押下
    2. ```searchCountry```を実行
        3. ```$rootScope.isLoading = true```でローディングを表示する
        4. ローディングの詳細は[[monaca]ui-router遷移時にローディング処理を入れてみた。](https://qiita.com/miz21358/items/fdbab7b1c0c4772ff96b#_reference-475de97a2cfb1d0b637d)参照。
        5. ```ng-model```で```$scope```にバインドされた```searchText```を取得
        6. ```$scope.searchText```を引数に、```JsonCountryService```を実行
1. ```JsonCountryService```内部の処理
    7. ```country.json```を取得
        8. 取得に成功した場合
            9. 検索文字列が指定されている場合
                10. ```$filter("filter")(response.data.list, searchText, false)```
                11. 第一引数: 検索対象リスト
                12. 第二引数: 検索文字列(検索範囲を絞り込みたい場合は、``` { "country": searchText }```のように指定する
                13. 第三引数：false: 部分一致検索, (true: 完全一致検索)
                14. フィルタ結果を返す
            10. 検索文字列が指定されていない場合
                11. 検索結果全件を返す
        12. 取得に失敗した場合
            13. エラーメッセージを返す
1. ```JsonCountryService```から結果リストが戻ってきた場合
    2. 検索結果件数を```message```に設定
    3. 検索結果リストを```list```に設定
    4. ローディング終了
5. ```JsonCountryService```から結果リストが戻ってこなかった場合
    6. エラーメッセージを```message```に設定
    4. ローディング終了
6. ```ng-repeat```で検索結果リストの内容をリスト表示する
    7. ```dd```タグは、```shown[i]```がtrueの場合のみ表示する。（初期表示時、false）
    8. ```dt```タグ押下時、```shown[i]```の値を反転する
        9. ```dd```タグ表示のタイミングで、```dd.ng-hide-remove```スタイルクラスが実行され、```bounceInLeft```アニメーションが実施される
        10. ```dd```タグ非表示のタイミングで、```dd.ng-hide-add```スタイルクラスが実行され、```bounceOutLeft```アニメーションが実施される
        11. アニメーションの詳細は、[[monaca]ui-routerで詳細スワイプ処理](https://qiita.com/drafts/b14675043893b94c2177)参照。
    11. ```shown[i]=true```の場合、```fa-chevron-circle-down```アイコンを表示する
    11. ```shown[i]=false```の場合、```fa-chevron-circle-right```アイコンを表示する

# ソースコード

https://github.com/miz21358/ui-router-search-sample