えいのうにっき

むかしのじぶんのために書いています

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