通过使用RequireJS动态加载AngularJS控制器

点击HogeController的按钮后,使用requirejs加载控制器和模板,将模板的内容添加到testWidget中。添加的内容与加载的控制器相关联,因此当点击按钮时,加载的控制器的事件将被触发。

[HTML画面]

<!DOCTYPE html>
<html lang="ja" >
  <head>
    <meta charset="utf-8">
    <title>angular require test 1</title>
    <!-- requiejsのエントリ -->
    <script data-main="dist/js/app/boot.js?hoge" src="dist/js/lib/require.js"></script>
  </head>

  <body>
    <div ng-controller="HogeController as HogeC">
      <button type="button"  ng-click="HogeC.doClick()" >click</button>
    </div>
    <div>hello</div>
    <div>
      <testWidget>
        <!-- 上のボタンを押すとコントローラーをロードして、ここにテンプレートの内容を挿入する -->
      </testWidget>
    </div>

  </body>
</html>

点击按钮,插入testWidget的内容模板。

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

[初始阶段的JS加载]

require.config({
    paths: {
        'angular':           'lib/angularjs/angular'
        ,'jquery':           'lib/jquery/jquery-2.1.0'
        ,'app':              'app/app'
        ,'hoge_controller':  'app/hoge_controller_define'
        ,'fuga_controller':  'app/fuga_controller_define'
    }

    ,shim: {
        "angular":           {"deps": ["jquery"] ,"exports": "angular"}
        ,"app":              {"deps": ["angular"]}
        ,"hoge_controller":  {"deps": ["app"]}
        ,"fuga_controller":  {"deps": ["app"]}
    }

    ,baseUrl: 'dist/js'

    // cache防止
    ,urlArgs: 'bust=' + (new Date()).getTime()
});

require([
    'jquery' ,'angular' ,'app' ,'hoge_controller'
], function(jQuery ,angular ,app) {

    console.log('boot app start.');

    // DOMロード時、実行
    $(function() {
        angular.bootstrap(document, ['app']);
        console.log("boot app end.");
    });
});

[Angular应用配置js]

define([
    'angular' ,
    'jquery' 
], function (angular ,jQuery) {

    // angularアプリケーションの初期化
    var app = angular.module('app' ,[]);
    // bootstrap後にcontrollerを追加出来るよう、controllerProvider設定
    app.config(function($controllerProvider, $compileProvider, $filterProvider, $provide)
    {
        app.controllerProvider = $controllerProvider;
        app.compileProvider    = $compileProvider;
        app.filterProvider     = $filterProvider;
        app.provide            = $provide;
    });

    return app;
});

[Angular 控制器 JavaScript 文件]

define([
    'angular',
    'jquery',
    'app'
], function (angular ,jQuery ,app) {

    // HogeController定義
    // このコントローラーは、angular.bootstrapまでに読み込まれる。
    // なので、コントローラーの定義は、controller()で行う。
    app.controller('HogeController' ,[
        '$scope', '$compile', '$http',
        function($scope ,$compile ,$http) {

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

                // testWidgetに追加されてない場合、ロードして追加。
                var elm = angular.element('testWidget testWidgetSub');
                if (elm.size() == 0) {

                    // FugaControllerを動的にロード
                    require([
                    'jquery' ,'angular' ,'app' ,'fuga_controller'
                    ], function(jQuery ,angular ,app) {

                        // テンプレートを動的にロード
                        $http.get('dist/template/test_template.html')
                            .success(
                                function(data,status,headers,config) {

                                    // ロードしたテンプレートをコンパイルして
                                    // testWidgetに追加
                                    var hogeViewTmpl = $compile(data)($scope);
                                    app.directive('testWidgetSub' ,
                                                  function(scope) {
                                                      scope.$apply();
                                                  });
                                    angular.element('testWidget').append(hogeViewTmpl);

                                })
                            .error(
                                function(data,status,headers,config) {
                                    console.log('load template failed .');
                                }
                            );

                    });

                }

            } 
        }
    ]);

    // angular.bootstrap()してないので、
    // angular.controller('HogeController')は返せない...
    return app;
});

[angular控制器js(在bootstrap之后)]

define([
    'angular',
    'jquery',
    'app'
], function (angular ,jQuery ,app) {

    // FugaController定義
    // このコントローラーは、HogeController.doClickのイベントで読み込まれる。
    // なので、コントローラーの定義は、controllerProvider.register()で行う。
    app.controllerProvider.register('FugaController', [
        '$scope', '$compile', '$http',
        function($scope ,$compile ,$http) {
            $scope.doFuga = function() {
                console.log('fuga controller clicked!!!');
            };
        }
    ]);

    return app.controller('FugaController');
});

●随想
变得结构繁琐的处理方式。
是不是前提要一次性全部加载?
即使在有很多屏幕并需要分成层次结构的情况下,SPA是否需要一次性全部加载?

我还没有调查过这项服务,但是仍然需要提供者吗?

我需要调查是否可以后续添加 require.config 的 paths。(要么不能,要么会变得非常繁琐的处理,如果在 require 时指定路径并附加文件扩展名进行加载,但效果一般…)

想要从angular模块的外部调用$http.get,来调查是否可以更改模板获取的时机。

用Backbone写一遍,看写出来是否清晰。

bannerAds