The Round

合同会社ナイツオの開発ブログ

静岡でGo言語やりたい人!!→こちら

AngularJSではjQueryを使わない

AngularJSではjQueryを使わない

どうもマツウラです。 AngularJSでjQueryプラグインを使う方法を調べました。

結論から書くとなるべくdirectiveで書きなおして下さい、ということです。 プラグインをそのまま使いたい気持ちはありますが、理由があるんです。


まず、AngularJSで使う方法をみてみます。

  1. プラグインが適用されない。
  2. directiveのlink関数に書く。
.directive('myDirective', function() {
  return {
    link: {
      post: function(scope, element, attr) {
        //...
      }
    }
  }
})
  1. 動的に生成されたDOMに対してプラグインが適用されない。
  2. $timeoutを使う。
$timeout(function() {
  //...
},0)

簡単なプラグインであれば直接書き換える方法もあります。

jQueryのイベント処理は$scope.$applyを使って実行する必要があります。

jQuery(selector).someEvent(function(){
    $scope.$apply(function(){
      // ここでangularアプリのモデル変更やメソッドの呼び出しを行う。
    });
});

参考:jQuery and AngularJS: Bind Events to Changing DOM

これらの方法で解決できそうですが、推奨されません。
その理由を見てゆきます。

stackoverflow:How do I “think in AngularJS” if I have a jQuery background?の投稿にまとまっています。(回答はVote 4000以上の評価)

役割がjQueryとAngularJSで異なる

  • jQueryは既に構築されたページに対する補強用に設計されたもの
  • AngularJSはアプリのデザインから始まり、ページのデザインを行う。

jQueryを使っているとAngularJSに慣れない

AngularJSとjQueryを一緒に使うと2つのコードが混ざる。
無理やりAngularJS用にjQueryプラグインをcallbackや$applyを使って書くよりも、純粋にAngularJSで書きなおしたほうが分かりやすく、簡単に書ける。

ただし、解決策がない場合にはjQueryを使う。

アーキテクチャの観点から

まずAngularJSはシングルページアプリであり、Webページではない。
なのでクライアントサイドに加えてサーバーサイドの開発者の視点でも考える必要がある。
独立しており、拡張可能であり、テスト可能であるようにアプリを分割するように考える。

テスト駆動開発

多くのjQuery pluginにはテストスイートが無いから。

jQueryではテストを行う際は独立したページを作成して実際に動作確認をする場合が多い。けれどもAngularJSでは別々のコンポーネントを作成して、アプリで統合する必要がある。

directiveはjQueryをパッケージしたものではない

次の例が考えられる。

.directive( 'myDirective', function () {
  return {
    template: '<a class="btn">Toggle me!</a>',
    link: function ( scope, element, attrs ) {
      var on = false;
      $(element).click( function () {
        if ( on ) {
           $(element).removeClass( 'active' );
        }
        else {
           $(element).addClass( 'active' );
        }
        on = !on;
      });
    }
  };
});

これではロジックであるべきdirectiveにテンプレートの操作を行う処理が混在してしまう。 AngularJSではこのように書く。

.directive( 'myDirective', function () {
  return {
    scope: true,
    template: '<a class="btn" ng-class="{active: on}" ng-click="toggle()">Toggle me!</a>',
    link: function ( scope, element, attrs ) {
      scope.on = false;
      scope.toggle = function () {
        scope.on = !scope.on;
      };
    }
  };
});

ロジックとテンプレートは分離して再利用可能にする。 directiveはjQueryのような機能群ではなく、実際にはHTMLを拡張したもの。

詳しくはリンク先を見てください。

このようにAngularJSでjQueryをつかうことで生じる問題が指摘されています。

ただjQueryには素晴らしいUI系プラグインが山ほどあります。
どうしても使いたいのなら、自力でdirectiveに書き起こすのが近道のようです。
その際に参考になるFAQが公式にあります。
FAQ:Trying to duplicate functionality that already exists
プラグインをdirectiveとして書き直すことを考えている方は見てみてください。