Onsen UIでテンプレートを使う時の注意点

はじめに

知人に「このJSが動かないんだけど・・・」
と聞かれ調査した時のことを備忘録として書いておきたいと思います。

やりたいこと

要件としては、Onsen UIでbxSliderを使うというもので、 Onsen UIを見たところ、jQuery等も動くとあったため使えそうではありました。

シンプルなサンプルを作ってみる

まずはbxSliderを動かすためだけのもので試してみます。

monacaの準備

Onsen UIはMonaca上で動くきます。 なのでMonacaの環境を整えてあげます

## 適当なディレクトリで
% sudo npm install -g monaca
% monaca create sample
% # "Onsen UI" -> "Onsen UI V1 Minimum" を選択
% cd sample
% monaca preview

これでベースの準備は完了です。

bxSliderを入れてみる

1.bxSliderをダウンロード

公式サイトからスクリプトをダウンロードし、 うえで作ったディレクトリ内のwww直下に設置します。

2.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:; style-src * 'unsafe-inline'; script-src * 'unsafe-inline' 'unsafe-eval'">
    <script src="components/loader.js"></script>
    <link rel="stylesheet" href="components/loader.css">
    <link rel="stylesheet" href="css/style.css">

    <script>
        ons.bootstrap();
    </script>

    <!-- #bxSlider(Script)ここから -->
    <script src="https://code.jquery.com/jquery-1.12.4.js"></script>
    <link href="jquery.bxslider/jquery.bxslider.css" rel="stylesheet">
    <script src="jquery.bxslider/jquery.bxslider.min.js"></script>
    <script>
        ons.ready(function() {
            $('.bxslider').bxSlider();
        });
    </script>
    <!-- #bxSlider(Script)ここまで -->

</head>
    <body>
        <ons-page>
            <!-- #bxSlider(markup)ここから -->
            <div style="width: 500px; margin: auto">
                <ul class="bxslider">
                    <li><img src="http://ja.onsen.io/images/logo/onsen_with_text.png"></li>
                    <li><img src="http://ja.onsen.io/images/logo/onsen_with_text.png"></li>
                    <li><img src="http://ja.onsen.io/images/logo/onsen_with_text.png"></li>
                    <li><img src="http://ja.onsen.io/images/logo/onsen_with_text.png"></li>
                    <li><img src="http://ja.onsen.io/images/logo/onsen_with_text.png"></li>
                </ul>
            </div>
            <!-- #bxSlider(markup)ここまで -->
        </ons-page>
    </body>
</html>

3.previewしてみる

% monaca preview

f:id:hades-netherworld-service:20160522220851p:plain 動くやん。

知らされる真実

どうやら先方のやりたいことは、ons-templateタグ内で上のものを動かしたいということでした。
ちゃんと話を聞くことは大事ですね。

先方が作っていた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:; style-src * 'unsafe-inline'; script-src * 'unsafe-inline' 'unsafe-eval'">
    <script src="components/loader.js"></script>
    <link rel="stylesheet" href="components/loader.css">
    <link rel="stylesheet" href="css/style.css">

    <script>
        ons.bootstrap();
    </script>

    <script src="https://code.jquery.com/jquery-1.12.4.js"></script>
    <link href="jquery.bxslider/jquery.bxslider.css" rel="stylesheet">
    <script src="jquery.bxslider/jquery.bxslider.min.js"></script>
    <script>
        ons.ready(function() {
            $('.bxslider').bxSlider();
        });
    </script>

</head>
    <body>
      <!-- ons-templateを利用 ここから -->
      <ons-navigator page="list.html" var="navi"></ons-navigator>
      <ons-template id="list.html">
      <!-- ons-templateを利用 ここまで -->
        <ons-page id="list-page">
            <div style="width: 500px; margin: auto">
                <ul class="bxslider">
                    <li><img src="http://ja.onsen.io/images/logo/onsen_with_text.png"></li>
                    <li><img src="http://ja.onsen.io/images/logo/onsen_with_text.png"></li>
                    <li><img src="http://ja.onsen.io/images/logo/onsen_with_text.png"></li>
                    <li><img src="http://ja.onsen.io/images/logo/onsen_with_text.png"></li>
                    <li><img src="http://ja.onsen.io/images/logo/onsen_with_text.png"></li>
                </ul>
            </div>
        </ons-page>
      </ons-template>
    </body>
</html>

ons-templateでラップしただけなので一見動きそうですが、上記をpreviewしてみると、動いていないことがわかります。

動くようにしてみる

原因はons.readyfunctionが発火した時にはまだons-navigatorにtemplateが描画されていないために、 処理対象の要素がないことです。
こういう時のために、Onsen UIではons-navigatorに幾つかのイベントが用意されています。(詳しくはここ
これを使うことで、対象のtemplateがロードされてから処理の関数を動かすことが出来るようになります。

<!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:; style-src * 'unsafe-inline'; script-src * 'unsafe-inline' 'unsafe-eval'">
    <script src="components/loader.js"></script>
    <link rel="stylesheet" href="components/loader.css">
    <link rel="stylesheet" href="css/style.css">

    <script>
        ons.bootstrap();
    </script>

    <script src="https://code.jquery.com/jquery-1.12.4.js"></script>
    <link href="jquery.bxslider/jquery.bxslider.css" rel="stylesheet">
    <script src="jquery.bxslider/jquery.bxslider.min.js"></script>

</head>
    <body>
      <ons-navigator page="list.html" var="navi"></ons-navigator>
      <ons-template id="list.html">
        <!-- 修正ここから -->
        <script>
            ons.ready(function() {
                navi.on('postpush', function(e) {
                  $('.bxslider').bxSlider();
                });
            });
        </script>
        <!-- 修正ここまで -->
        <ons-page id="list-page">
            <div style="width: 500px; margin: auto">
                <ul class="bxslider">
                    <li><img src="http://ja.onsen.io/images/logo/onsen_with_text.png"></li>
                    <li><img src="http://ja.onsen.io/images/logo/onsen_with_text.png"></li>
                    <li><img src="http://ja.onsen.io/images/logo/onsen_with_text.png"></li>
                    <li><img src="http://ja.onsen.io/images/logo/onsen_with_text.png"></li>
                    <li><img src="http://ja.onsen.io/images/logo/onsen_with_text.png"></li>
                </ul>
            </div>
        </ons-page>
      </ons-template>
    </body>
</html>

ざっくり解説

まず、ons-navigatorのイベントを取得するために、navigator自身の名前を決めてあげます。
それがvar属性です。

nagivatorにイベントを設定するためにはjQueryでお馴染みのon関数を用います。 その際のイベント名はイベントを発火させたいタイミングによります。(今回はpostpushを利用しました)

このイベントにひも付けた関数内で、実行したい処理を記述することで、 動かなかった処理たちを動かすことが出来るようになります。

おわりに

Onsen UIには明るくないのですが、 そりゃtemplateを使っていたらそれがロードされるまでは要素見つからないですよねってことです。
(なんとか解決できてよかった)