えいのうにっき

a-knowの日記です

AngularJSで動的に生成されるDOMに対して、jQueryプラグインの効果を適用する

お久しぶりです

お久しぶりです、a-knowです。 ブログを書くのは、昨年の12/11以来、半年弱ぶりですか・・・(汗) この半年、本当にいろいろありました。(思い出したくもないこともちらほらと・・・w)

お仕事の方も、今までやっていたPJとは違う、新しいPJが動き始めたということもあって、 バージョン管理をsvnからgitに変えたり(やっと!)、Jenkinsを導入したり、自社開発基盤を刷新したり・・・と、 技術的にも色んな新しいことに挑戦できている毎日なんですが、 AngularJSも、そのうちの一つだったりします。

AngularJSでつまづいたところ

それにしてもAngularJS、非常に痛快ですね! たとえば、jQueryで長々と書いていたDOM操作の為の記述が、ほぼいらなくなっちゃう。これはホントに痛快です。 最近は参加できていませんが、今後ハッカソンプログラミングコンテストなどの開発スピードが求められるような場に参加した際にも、デフォで使っちゃうだろうなー、というくらいに便利です。

そんな便利なAngularJSなんですが、やはりちょこちょこと躓いたりもしてます。 minify対策なんかもそうなんですが、 最近で一番手間取っちゃったのが、表題の「動的に生成されるDOMに対して、jQueryプラグインの効果を適用する」という点。

jQueryスライダプラグイン「flickslide」を利用するのに手間取った

例をわざわざ用意するのも面倒なので、実際に躓いた事象を挙げます。 利用したのは、jQueryスライダプラグインflickslide」。モバイル向けにバナー画像を一定間隔でローテーションさせるUIを生成してくれるプラグインですね。 で、ローテーション対象である画像のDOMをAngularJSで生成している、と。 このflickslideに限らず、こういうかんじのプラグインは多いと思います。

では事例を。htmlはこんな感じで書きます。

<div id="mainImages" class="mainImageInit">
    <ul>
        <li ng-repeat="image in images">
            <img ng-src="{{image.imageUrl}}">
        </li>
    </ul>
</div>

で、これにflickslideを適用するために、普通ならこう書けばいいんだけど、

$(function(){
    $('#mainImages ul li').flickSlide({target:'#mainImages>ul', duration:5000});
});

これだと、AngularJSで動的に生成されたDOMに対して正しく適用させることができない。 どうするか。

directiveを設定するのが正解っぽい。 directiveってなんぞや、ってところですけど、「ng-hoge」みたいなものを自分で定義・設定できるようになる、みたいな感じの理解です。

まず、ng-appを設定して、

<html lang="ja" ng-app="testApp">

directiveを設定。

angular.module('testApp', [])
    .directive('flSlide', function factory() {
        return function postLink(scope, iElement, iAttrs) {
        //ごにょごにょする
        }
    };
})
<div id="mainImages" class="mainImageInit">
    <ul>
        <li ng-repeat="image in images" fl-slide>
            <img ng-src="{{image.imageUrl}}">
        </li>
    </ul>
</div>

JSの方で「flSlide」と設定すれば、htmlの方では「fl-slide」と、こういう書き方になります。 んで、「iElement」は、そのdirectiveが設定された要素を指すイメージ。 なのでこの例だと、「images」のサイズが5だと、directiveも5回、呼び出されるかんじ。

この「ごにょごにょ」のところに、実施したいことを記述するわけで、 今回の場合は

$(function(){
    $('#mainImages ul li').flickSlide({target:'#mainImages>ul', duration:5000});
});

これに相当することを書きたいわけで、 「iElementは '#mainImages ul li' と同じだから〜・・・」とかいろいろ考えちゃうんですが、 flickslideの場合でいうと、結論、下記のように書くのが正解っぽい。

angular.module('testApp', [])
    .directive('flSlide', function factory() {
        return function postLink(scope, iElement, iAttrs) {
            //最後の一回だけ適用
            if(scope.$last === true){
                $('#mainImages ul li')
                    .flickSlide({target : '#mainImages>ul', duration : 5000});
            }
        }
    };
});

自分的には、ずっとiElementを使おうとして(使わなきゃいけないと思って)躓き続けちゃっていました。 元々の記述で行われる処理をdirectiveで実施するだけ、というふうに、はやく頭を切り替えられれば良かった。。

(ちなみにこのflickslideプラグイン、コードにプログラムミスがあると思うんだよなぁ。。いくらdurationに値を設定しても、実際のアニメーションには反映されない。自分で直しちゃったけど。。)

おまけ・AngularJSを使って開発をスタートするためにやったこと

ドットインストール。全部見ても30分。全くの予備知識もないところに見るのには最適。 公式サイトAPIリファレンスがすごく探しやすい。最終的な検索結果とはあまり関係のないワードを入力しても、結構目的のページに行き着けちゃう印象。

・・・僕はこれだけ。w あとはひたすら作る!手を動かす!・・・これですね☆

(仕事仲間もつぶやいてたんだけど、例えばng-controllerの好ましい設定範囲は?とか、AngularJSに関してはまだまだ疑問は尽きないかんじ。ぜひ勉強会とかに参加して基礎を固めたいな、というところ。)

関連エントリ

blog.a-know.me

AngularJSリファレンス

AngularJSリファレンス

Webアプリ構築のためのAngularJS

Webアプリ構築のためのAngularJS

follow us in feedly