opensocialガジェットをAngular.jsで実装する

| コメントをどうぞ

opensocialガジェットをAngular.jsで作ってみました。引っかかった箇所をご紹介です。
※コードはinfoScoopのガジェット用

コツ1: angularアプリを手動で起動する

angular.jsは、自動と手動、2種類の初期化方法を選ぶことができます。
自動の場合は、ng-appをhtml上に指定する必要があります。すると、htmlが読み込まれたタイミングで自動で初期化が行われます。普通は自動の手法でやることがほとんどでしょう。

一方ガジェットの場合は、手動で初期化する必要があります。
ガジェットでscriptを読む準備ができたタイミングで初期化を行わなければならないからです。
下記のように、gadgets.util.registerOnLoadHandlerを利用し、ガジェットの準備ができた段階でangular.bootstrap~を呼び、手動で初期化しましょう。

test.xml

<?xml version="1.0" encoding="UTF-8"?>
<Module>
...
    <Content type="html">
        <![CDATA[
...
<script src="__IS_GADGET_BASE_URL__/vendors/angular.js"></script>
<script src="__IS_GADGET_BASE_URL__/js/app.js"></script>
<script>
    gadgets.util.registerOnLoadHandler(init);
</script>
    ]]>
    </Content> 
</Module>

app.js

var init = function (){
    'use strict';
    var app = angular.module('app', []);
    angular.bootstrap(document, ['app']);
}

コツ2: Angular.jsのルーティングは使わない

使わない、というか、動きませんでした。
よって代替の実装にしました。
page変数にページ名を代入し、その判定をng-showで行うことでページ切り替えができるようにしました。

test.xml

<?xml version="1.0" encoding="UTF-8"?>
<Module>
    ...
    <Content type="html">
    <![CDATA[
<body>
    <div>
        <div id="main" ng-controller="MainController">
            <div ng-show="page == 'page1'" oa-adjust-height="page1">
                <h3>Page 1</h3>
                <div>{{fetchedData1}}</div>
                <br>
                <button ng-click="showPage2()">Next</button>
            </div>
            <div ng-show="page == 'page2'" oa-adjust-height="page2">
                <h3>Page 2</h3>
                <div>{{fetchedData2}}</div>
                <br>
                <button ng-click="showPage3()">Next</button>
            </div>
            <div ng-show="page == 'page3'" oa-adjust-height="page3">
                <h3>Page 3</h3>
                <div>{{fetchedData3}}</div>
                <br>
                <button ng-click="showPage1()">Go back to page 1</button>
            </div>
        </div>
    </div>

<script src="__IS_GADGET_BASE_URL__/js/app.js"></script>
<script src="__IS_GADGET_BASE_URL__/js/services.js"></script>
<script src="__IS_GADGET_BASE_URL__/js/controllers.js"></script>
<script src="__IS_GADGET_BASE_URL__/js/directives.js"></script>
...
</body>
    ]]>
    </Content> 
</Module>

controller.js

var ctlModule = angular.module('app.controllers', []);
ctlModule.controller('MainController', ['$scope', 'ContentsGetter', function($scope, ContentsGetter){
    $scope.showPage1 = function(){
        ContentsGetter.page1().then(function(data){
            $scope.fetchedData1 = data;
            $scope.page = 'page1';
        });
    };

        //$scope.showPage2,3も同様
    ...
     
    $scope.showPage1();
}]);

コツ3 高さ調整

高さ調整に苦労しました。
page変数の変更を監視して高さを取るのですが、DOMの描画前に取得されてしまうようで、0で取れてしまいます。
DOMの描画完了時のタイミングは知ることはできないため、苦肉の策できれいなやり方ではないですが、下記のような実装に。
$intervalでタイマーを仕掛け、二回続けて高さが同じであればタイマーを外して高さをセットするというもの。
xmlは上記と同じです。

directives.js

var dirModule = angular.module('app.directives', []);

dirModule.directive('oaAdjustHeight', ['$interval', function($interval){
    return {
        link: function postLink (scope, iElement, iAttrs){
            var height;
            var tempHeight;

            scope.$watch('page', function(newVal, oldVal){
                if(newVal == iAttrs.oaAdjustHeight){
                    var interval = $interval(function() {
                        height = iElement[0].clientHeight;
                        if (tempHeight == height){
                            $interval.cancel(interval);
                            gadgets.window.adjustHeight();
                        }
                        if (height > 0){
                            tempHeight = height;
                        }

                    }, 200);
                }
            });

        }
    }
}]);

全体のコードはgithubに公開しています。
zipファイルをinfoScoopにアップロードすればそのままサンプルとして動作します。

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

次のHTML タグと属性が使えます: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>