JSON
AngularJS
ui-router
monaca
onsenui

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

More than 1 year has passed since last update.

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

ベース

ui-routerでjsonを取得したリスト画面
[monaca]ui-routerでjson取得処理。

angular-animateの導入

詳細は、[monaca]ui-routerで詳細スワイプ処理参照。

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

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

ソースコード

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