はじめに
みなさん、こんにちは!
今回は、OnsenUIがOnsenたる理由である、SPA(Single Page Application)のアプリを作りましょう。
SPA = スパ = Onsen ということらしいですね。はい。
OnsenUIでSPAしなかった今までが逆に宝の持ち腐れだったということですね。はい。
単にページ遷移しておしまい、というのはあんまりなので、今回も何かのアプリを作りつつやっていきましょう。
今回は、Amazon Suggest APIを使用して、
とあるキーワードを投げる⇒そのキーワードの関連キー一覧を取得⇒さらにそのキーワードを選択して関連キー一覧を取得
みたいなアプリを作ることにしましょう。
ons-navigatorについて
OnsenUIには、いくつかのページ管理方式があり、それらを組み合わせて使用することもできます。
が、今回はナビゲーション型のページ管理にしましょう。
これは、ルート(親)になる画面から、子の画面に遷移していくようなパターンのアプリに向くページ管理方式です。
割と多くのアプリに当てはまると思います。
使用するためには、HTMLにons-navigator要素を配置します。
[html] <ons-navigator var="myNav" page="main.html"></ons-navigator>[/html]
var属性は、このディレクティブに限らず、OnsenUIで共通的に使用できます。
Javascriptのコード内で参照できる変数名を与えることができます。
page属性は、アプリが起動した時に、どのテンプレートページを表示するかを指定できます。
また、OnsenUIでは、テンプレートをサポートしています。
ons-templateタグでHTMLのテンプレートを記述すれば、後にテンプレートを使用できます。このテンプレートにidを与えることで、参照が可能です。
テンプレートを使用しないで、htmlファイル自体を分けることももちろん可能です。
ここから実装です
さて。
それでは、実装を始めていきましょう。
今回ももちろん、OnsenとAngularを使用するので、前回と同様にライブラリを配置しておいてください。
index.html
まずは、HTMLファイルを編集していきます。
【www/index.html】
[html] <html> <head>
<meta charset="utf-8" />
<meta name="format-detection" content="telephone=no" />
<meta name="msapplication-tap-highlight" content="no" />
<!– WARNING: for iOS 7, remove the width=device-width and height=device-height attributes. See https://issues.apache.org/jira/browse/CB-4323 –>
<meta name="viewport" content="user-scalable=no, initial-scale=1, maximum-scale=1, minimum-scale=1, width=device-width, height=device-height, target-densitydpi=device-dpi" />
<link rel="stylesheet" href="lib/onsen/css/onsenui.css" />
<link rel="stylesheet" href="lib/onsen/css/onsen-css-components-blue-basic-theme.css" />
<script src="lib/onsen/js/angular/angular.js"></script>
<script src="lib/onsen/js/onsenui.js"></script>
<script src="js/mainController.js"></script>
<style>
ons-page{
font-family: "ヒラギノ角ゴシック Pro", "Hiragino Kaku Gothic Pro", ‘メイリオ’ , Meiryo , Osaka, "MS Pゴシック", "MS PGothic", sans-serif !important;
}
#input_searchkey{
width: 100%;
height: 48px;
font-size: 42px;
margin-top: 4px;
margin-bottom: 4px;
}
.delete-button{
background-color: rgb(240, 80, 80);
}
.op-buttons ons-button{
width: 100%;
text-align: center;
}
.result{
font-size: 32px;
}
.result > p{
margin: 4px;
}
</style>
<script type="text/javascript" src="cordova.js"></script>
<title>Amazon Suggestion</title>
</head>
<body>
<ons-navigator var="myNav" page="main.html"></ons-navigator>
<ons-template id="main.html">
<ons-page ng-controller="MainPageController">
<ons-toolbar>
<div class="center">Amazon Suggestion</div>
</ons-toolbar>
<ons-row>
<input id="input_searchkey" type="text" ng-model="searchkey" />
</ons-row>
<ons-row>
<ons-button modifier="large" ng-click="searchSuggestion()"><ons-icon icon="search"></ons-icon>search</ons-button>
</ons-row>
</ons-page>
</ons-template>
<ons-template id="result.html">
<ons-page ng-controller="resultPageController">
<ons-toolbar>
<div class="left"><ons-back-button>Back</ons-back-button></div>
<div class="center">Amazon Suggestion</div>
<div class="right"><ons-button modifier="quiet" ng-click="move2top()">Home</ons-button></div>
</ons-toolbar>
<div>
<ons-list>
<ons-list-item ng-repeat="item in keywords" ng-click="recursiveSearch($index)">
{{item.keyword}}
</ons-list-item>
</ons-list>
</div>
</ons-page>
</ons-template>
</body>
</html>
52行目で今回のテーマであるons-navigatorを宣言しています。
var属性にはmyNavを与えています。これでjs側でmyNavとして参照することができます。
page属性には、main.htmlを与えています。テンプレートにmain.htmlというidを与えておくか、main.htmlというhtmlファイルを同階層に用意する必要がありますが、今回は前者でいきましょう。
54行目でtemplateを宣言しています。ここから70行目の/templateまでの間に記述された要素をid名main.htmlというテンプレートとして呼び出すことができます。
72行目から89行目まで、また別のテンプレートです。
こちらは、キーワード検索結果表示用のテンプレートとして使用します。
75行目で、ons-back-buttonを使用していますが、これは、ボタンが押下されるとnavigationの持つページスタックから自動で1ページ分ポップしてくれる便利なディレクティブです。
77行目は、キーワードを掘りすぎるとトップ画面に戻るのが大変そうだったので、Homeボタンを用意しています。クリックイベントをアタッチしていますので、コントローラ側でイベントを定義します。
mainController.js
今度は、コントローラ側です。
【www/js/mainController.js】
[javascript] {‘use strict’;
var module = ons.bootstrap("ONSEN_03_APP", [‘onsen’]);
module.controller("MainPageController", function ($scope) {
$scope.searchkey = "";
// 住所検索を行う
$scope.searchSuggestion = function(){
if(!!$scope.searchkey){
myNav.pushPage("result.html", { keyword: $scope.searchkey });
}
else{
alert("検索キーを入力してください…");
}
}
});
module.controller("resultPageController", function ($scope, $http, GetAmazonSuggestionsService){
$scope.keywords = [];
var nav_options = myNav.getCurrentPage().options;
GetAmazonSuggestionsService.getsuggestions(nav_options.keyword, function(res){
$scope.keywords = res.results;
});
$scope.recursiveSearch = function(index){
myNav.pushPage("result.html", {
keyword: $scope.keywords[index].keyword
});
};
$scope.move2top = function(){
myNav.resetToPage("main.html");
}
});
module.service("GetAmazonSuggestionsService", function ($http){
this.getsuggestions = function(searchkey, callback){
var params = {
q: searchkey,
method: "completion",
mkt: 6,
"search-alias": "aps",
callback: "JSON_CALLBACK"
};
// angularのhttpサービスでjsonp
$http.jsonp(
"http://completion.amazon.co.jp/search/complete",
{
params: params
}
).success(function(data){
console.log(data);
var search_title = data[0];
var search_result_arr = (function(items){
var res = [];
if(!items){ return res; }
for(var i = 0; i < items.length; i++){ res.push({keyword: items[i]}); }
return res;
})(data[1]);
callback({
searchkey: search_title,
results: search_result_arr
});
}).error(function(){
alert("エラーが発生しました");
});
}
});
}
[/javascript]
12行目で、html側で定義したNavigationオブジェクトであるmyNavを使用しています。
次ページに遷移するためには、pushPageメソッドを使用します。
第1引数には遷移先のページ名(htmlファイル又はテンプレート)、
第2引数には遷移先に渡すパラメータを指定できます。
今回の場合は、次ページに検索キーワードを渡して、検索⇒表示をしてもらう方向でいきたいので、検索キーをパラメータとして渡すようにしています。
24行目で、遷移先側ページのコントローラにて、受け渡されたパラメータを取得しています。
前画面からのパラメータの取得は、
[/javascript]
のように、ナビゲーションオブジェクトのgetCurrentPageメソッドの持つoptionsプロパティにアクセスすればokです。
26行目で、前画面からのキーワードを取得するサービスのメソッドを呼び出しています。
このサービスは41行目以降で定義しています。
30行目~34行目が、検索結果一覧のとあるキーワードを押下した時のイベントハンドラです。
再び自分自身のページに遷移(再帰)することで、キーワードの掘り下げを行っています。
36行目が、html側で定義したHomeボタンのハンドラです。
ナビゲーションオブジェクトのresetToPageメソッドで、引数にとったページに遷移し、ページスタックをリセットしています。
41行目~81行目が、Amazon Suggest APIをコールして、戻り値を組み立てるサービスの定義です。
与えるパラメータのうち、qは検索文字列、他のパラメータは…良く分かっていません…ネット情報です。こんな感じで与えると、いい感じのキーワード提案をしてくれます。
あとは、前回の住所検索APIコールと同様ですね。Angularのhttpサービスでajaxして、コールバックで受け取った値を編集して…のようなことを行っています。はい。
動作確認
さて!
こんな感じのコーディングをすると、実機では下記のような動きのアプリができているはずです。
初期画面はons-navigatorで指定したmain.htmlが表示されます。ここで、検索キーワードを入力してSearchボタンを押下します。
すると、myNav.pushPageで次画面に遷移し、キーワード検索結果が表示されます。
さらに、この検索結果をタップすると(この画面だとGN125 シート をタップ)、さらにキーワードを掘り下げます。
こんな感じですね!
OnsenUIのons-navigatorを使用すると、簡単に親子関係のSPA実装ができますよ!というお話でした。
今回は以上です!