[備忘録]angularjsでcontrollerを動的に追加する



controllerをイベントによって、動的にロードしたいが、
angular.bootstrap()実行後に、app.controller('XXX')で、追加しても、
Error: [ng:areq] Argument 'XXX' is not a function, got undefined
となってしまう。

↓

angular.config()で、controllerProviderを設定し、controllerProvider.register()で追加する。


●サンプル


下記、HTMLのHogeController#doClick()で動的にエレメントを追加し、
その中のボタンを押した時に、イベントを発生させる。

```index.html
<!DOCTYPE html>
<html lang="ja" >
  <head>
    <meta charset="utf-8">

    <title>angular test 1</title>
    <script src="dist/js/lib/jquery/jquery-2.1.0.js"></script>
    <script src="dist/js/lib/angularjs/angular.js"></script>
    <script src="dist/js/app/main.js?hoge"></script>

  </head>

  <body>
    <div ng-controller="HogeController as HogeC">
      <button type="button"  ng-click="HogeC.doClick()" >click</button>
    </div>
    <div>hello</div>
    <div>
      <testWidget/>
    </div>

  </body>
</html>

```

testWidgetに追加するエレメントは、下記。
ボタンクリックのイベントを実行する為に、FugaControllerを動的に追加する。

```
<testWidgetSub ng-controller='FugaController'>
  <div >tttt
   <button type='button'ng-click='doFuga()'>Fuga!</buffon>
  </div>
</testWidgetSub>
```

ロードするJSは以下。


```main.js

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

app.controller('HogeController' ,[
    '$scope', '$compile', 
    function($scope ,$compile ) {

        this.doClick = function() {
            console.log('click');

            var elm = angular.element('testWidget testWidgetSub');
            console.log(elm.size());


            if (elm.size() == 0) {
            // エレメントが、まだ、追加されてない場合

                // コントローラーを追加
                app.controllerProvider.register('FugaController', [
                    '$scope', '$compile',
                    function($scope ,$compile) {
                            $scope.doFuga = function() {
                                // fugaボタンを押した時のイベント
                                console.log('fuga controller clicked!!!');
                            };
                    }
                ]);

                var hoge = $compile("<testWidgetSub ng-controller='FugaController'><div >{{'tttt'}}<button type='button'ng-click='doFuga()'>Fuga!</buffon></div></testWidgetSub>")($scope);

                // 作ったエレメントのコンパイル
                app.directive('testWidgetSub' ,
                              function(scope) {
                                  scope.$apply();
                              });

                // エレメント追加                
                angular.element('testWidget').append(hoge);
                console.log('append testWidgetSub on testWidget!!!!!');
            } else {
                console.log('already append testWidgetSub....');
            }
        } 

    }
]);

// DOMのロード完了時に実行しないと、Chromeでエラーになる場合がある
// なので、とりあえず、jqueryで、angular.bootstrap()を、実行...
$(function() {
    // providerを登録
    app.config(function($controllerProvider, $compileProvider, $filterProvider, $provide)
    {
        app.controllerProvider = $controllerProvider;
        app.compileProvider    = $compileProvider;
        app.filterProvider     = $filterProvider;
        app.provide            = $provide;
    });

    // bootstrap実行
    angular.bootstrap(document, ['app']);

    console.log("angular bootstrapped...");

});

```

angular.module('app')宣言後、bootstrap前に、app.configを実行し、controllerProviderを設定する。
bootstrap後、controllerの定義は、controllerProvider.register()で行う。