質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.12%

JavaScriptからOnsenUI(HTML)を操作できていますが、何故操作できているかが分かりません

解決済

回答 1

投稿

  • 評価
  • クリップ 0
  • VIEW 1,431

akabee

AngularJS総合1位

質問内容

monacaを用いて、OnsenUI + AngularJSでモバイルアプリの開発を行っています。
動いてはいるのですが、疑問点があり質問させて頂きます。

下記コードのJavaScriptの5行目、「splitter.left.toggle();」が正常に動いている理由が分かりません。

「splitter」は一番上のHTMLのons-splitterの名称として定義しているものですが、
通常JavaScriptからHTMLの操作をするにはDOMを使用(document.getElementByIdなど)するか、
AngularJSでも$scopeを使用する必要があると認識しています。

ですが、下記コードは特に注釈付けをすることなく、「splitter」がJavaScriptから操作できています。
これは何故でしょうか?

私が認識できていないOnsenUIやAngularJS、JavaScriptの仕様があるのでしょうか。
どなたか下記コードが正常に動く理由をご教示いただけませんでしょうか

該当のソースコード(一部抜粋の形です)

<ons-splitter var="splitter">
  <ons-splitter-side page="sidemenu.html" side="left" width="220px" collapse swipeable>
    </ons-splitter-side>
  <ons-splitter-content page="paylist.html"></ons-splitter-content>
</ons-splitter>
<ons-page>
      <ons-toolbar ng-controller="ToolbarController as ToolbarC">
        <div class="left">
          <ons-toolbar-button ng-click="ToolbarC.toggle()">
            <ons-icon icon="ion-navicon" style="font-size:32px; width:1rem;"></ons-icon>
          </ons-toolbar-button>
        </div>
        <div class="center">
          ツールバー
        </div>
        <div class="right">
          <div class="toolbar-namebox">
          <br />
            userid<br />
            username
          </div>
        </div>
      </ons-toolbar>
</ons-page>
angular.module(MyApp)

.controller('ToolbarController', function() {
    this.toggle = function() {
        splitter.left.toggle();
    };
});

補足情報

アプリを開発するにあたってテンプレートとしたコードがあり、
元々はsplitterの前に「$scope」があったのですが、
個人的に$scopeはあまり利用したくなく、
ためしに外してみたところ正常に動いて驚きました。
ただ、調べてもその理由が分からない、という経緯があります。

上記コードは開発中のコードから一部抜粋したものです。
過不足ないとの認識ですが、もし不足情報があれば提供いたします。

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 1

checkベストアンサー

+1

 angular-onsenui.jsの中身を確認すると

  • 以下のような箇所があります
    これはangularjsのdirectiveという機能を使ってons-splitterタグを作っているのですが
    $onsen.declareVarAttribute(attrs, splitter);という処理が名前的にあやしいです。
angular.module('onsen').directive('onsSplitter', ['$compile', 'Splitter', '$onsen', function ($compile, Splitter, $onsen) {
    return {
...略
          $onsen.declareVarAttribute(attrs, splitter);
...略
  }]);

 declareVarAttributeの中身を確認すると

  • 中身を確認すると、varに指定した名前をthis._defineVar(varName, object);というメソッドで処理しています。
declareVarAttribute: function declareVarAttribute(attrs, object) {
  if (typeof attrs.var === 'string') {
    var varName = attrs.var;
    this._defineVar(varName, object);
  }
},

 _defineVarの中身を確認すると

  • setメソッドでons.componentBaseにvarの値を設定していることがわかります。
_defineVar: function _defineVar(name, object) {
          var names = name.split(/\./);

          function set(container, names, object) {
            var name;
            for (var i = 0; i < names.length - 1; i++) {
              name = names[i];
              if (container[name] === undefined || container[name] === null) {
                container[name] = {};
              }
              container = container[name];
            }
            container[names[names.length - 1]] = object;

            if (container[names[names.length - 1]] !== object) {
              throw new Error('Cannot set var="' + object._attrs.var + '" because it will overwrite a read-only variable.');
            }
          }

          if (ons.componentBase) {
            set(ons.componentBase, names, object);
          }
...略
  }]);
})();

 ons.componentBaseとは...

  • windowオブジェクトを設定していることがわかります。
function initOnsenFacade() {
    ons._onsenService = null;

    // Object to attach component variables to when using the var="..." attribute.
    // Can be set to null to avoid polluting the global scope.
    ons.componentBase = window;

 つまりvarに入れた内容は

  • <ons-splitter var="splitter">とするということは、「window.splitter」としているということなのでグローバルに「splitter」として使用することが出来るということになります。

 補足

  • windowオブジェクトを汚したくない、という場合はons.componentBaseに自分で作ったオブジェクトを指定することも出来ます。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/11/26 18:57

    回答ありがとうございます。「var」にそんな意味が・・・。グローバルに使えるようになっているということなのですね。
    それにしても、ドキュメントのこの箇所を参照しろとの回答が来るものと考えておりましたがソースコードを調べて頂いたとは恐縮です。
    逆に言えばソースコードに全て書かれているということですね。これからは私自身でも調べるようにしてみます。
    ご回答いただきありがとうございました。

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 90.12%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる