通过使用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写一遍,看写出来是否清晰。