├── .bowerrc ├── example ├── src │ ├── modules │ │ ├── module2 │ │ │ ├── testB.tpl.html │ │ │ ├── testBCtrl.spec.js │ │ │ └── testBCtrl.js │ │ └── module1 │ │ │ ├── testA.tpl.html │ │ │ └── testACtrl.js │ ├── data │ │ └── testA.json │ ├── sharedService.js │ ├── app.js │ └── index.html ├── .bowerrc ├── bower.json ├── README.md └── test │ └── test-main.js ├── .gitignore ├── bower.json ├── package.json ├── dist ├── angular-lazyload.min.js └── angular-lazyload.js ├── README.md ├── Gruntfile.js └── src └── angular-lazyload.js /.bowerrc: -------------------------------------------------------------------------------- 1 | { 2 | 3 | } 4 | -------------------------------------------------------------------------------- /example/src/modules/module2/testB.tpl.html: -------------------------------------------------------------------------------- 1 | id: {{id}} -------------------------------------------------------------------------------- /example/.bowerrc: -------------------------------------------------------------------------------- 1 | { 2 | "directory": "src/components" 3 | } 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.psd 2 | .idea 3 | /node_modules 4 | /src/components 5 | /example/src/components 6 | .DS_Store 7 | -------------------------------------------------------------------------------- /example/src/modules/module1/testA.tpl.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /example/src/data/testA.json: -------------------------------------------------------------------------------- 1 | [ 2 | {"name": "ABC", "id": 1}, 3 | {"name": "CCC", "id": 2}, 4 | {"name": "SDD", "id": 3}, 5 | {"name": "AFF", "id": 4} 6 | ] -------------------------------------------------------------------------------- /example/bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "angular-seajs-showcase", 3 | "dependencies": { 4 | "seajs": "*", 5 | "angular": ">=1.2.0-rc.3", 6 | "angular-route": ">=1.2.0-rc.3", 7 | "angular-mocks": ">=1.2.0-rc.3" 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /example/src/modules/module2/testBCtrl.spec.js: -------------------------------------------------------------------------------- 1 | define(function (require, exports, module) { 2 | 'use strict'; 3 | require('./testBCtrl.js'); 4 | describe('controllers', function(){ 5 | beforeEach(module('app')); 6 | it('should ....', inject(function() { 7 | 8 | })); 9 | }); 10 | 11 | }); -------------------------------------------------------------------------------- /example/src/sharedService.js: -------------------------------------------------------------------------------- 1 | define(function (require, exports, module) { 2 | "use strict"; 3 | module.exports = function(app){ 4 | app.factory('sharedService', function(){ 5 | return { 6 | test: function(){ 7 | console.log('loaded service') 8 | } 9 | } 10 | }) 11 | } 12 | }); -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "angular-lazyload", 3 | "version": "0.4.0", 4 | "author": "TZ ", 5 | "description": "A lazyload service for angular projects, only load-on-demand, support seajs/requirejs/custom.", 6 | "main": ["dist/angular-lazyload.js"], 7 | "repository": { 8 | "type": "git", 9 | "url": "https://github.com/atian25/angular-lazyload" 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /example/src/modules/module2/testBCtrl.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 无需外部传入的app, 则直接执行即可 3 | */ 4 | define(function (require, exports, module) { 5 | 'use strict'; 6 | var app = require('app'); 7 | 8 | //注册controller 9 | app.register.controller('testBCtrl', ['$scope', '$routeParams', '$location', '$http', 10 | function($scope, $routeParams, $location, $http){ 11 | //获取页面的入参 12 | var id = $routeParams.id; 13 | $scope.id = id; 14 | }] 15 | ); 16 | 17 | }); -------------------------------------------------------------------------------- /example/README.md: -------------------------------------------------------------------------------- 1 | ## 源码目录 2 | 3 | - src 4 | - images 图片 5 | - css 样式 6 | - modules 本项目用到的模块, 按模块划分 7 | - module1 具体某个模块 8 | - module1.js 模块用到的js 9 | - module1.spec.js 对应的单元测试 10 | - module1.tpl.html 模板文件 11 | - module2 12 | - ... 13 | - commons 存储我们的通用模块,后期再独立为component 14 | - components 存储第三方的web类库,通过bower来安装,不存储到源码库. 15 | - conf 配置文件 16 | - urlmapping.conf 路由映射 17 | - prototype 存储R.E.D提供的原始HTML+CSS 18 | - test 存储测试相关的一些数据和脚本 19 | - Gruntfile.js 脚本定义 20 | - package.json 自述文件,版本号等信息 21 | - bower.json 定义需要安装到src/components的第三方web类库 22 | - node_modules 开发期需用到的nodejs插件, 无需纳入源码管理, 通过`npm install`安装. 23 | -------------------------------------------------------------------------------- /example/test/test-main.js: -------------------------------------------------------------------------------- 1 | var alias = {}; 2 | for (var file in window.__karma__.files) { 3 | if (window.__karma__.files.hasOwnProperty(file)) { 4 | if (/\/src\//.test(file)) { 5 | var name = file.replace(/^\/base\/src/, '.').replace(/\.js$/, ''); 6 | console.log('>',name, file) 7 | alias[name] = file; 8 | } 9 | } 10 | } 11 | 12 | seajs.config({ 13 | base: './', 14 | alias: alias 15 | }) 16 | 17 | var _fn = window.__karma__.start; 18 | window.__karma__.start = function() { 19 | seajs.use([ 20 | './app', 21 | './modules/module2/testBCtrl.spec' 22 | ], function(m) { 23 | angular.bootstrap(document, ['app']); 24 | _fn.call() 25 | }) 26 | } -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "angular-lazyload", 3 | "version": "0.4.0", 4 | "author": "TZ ", 5 | "description": "A lazyload service for angular projects, only load-on-demand, support seajs/requirejs/custom.", 6 | "repository": { 7 | "type": "git", 8 | "url": "https://github.com/atian25/angular-lazyload" 9 | }, 10 | "devDependencies": { 11 | "grunt": "latest", 12 | "grunt-contrib-clean": "latest", 13 | "grunt-contrib-concat": "latest", 14 | "grunt-contrib-copy": "latest", 15 | "grunt-contrib-connect": "latest", 16 | "grunt-contrib-htmlmin": "latest", 17 | "grunt-contrib-uglify": "latest", 18 | "grunt-contrib-watch": "latest", 19 | "matchdep": "latest", 20 | "connect-livereload": "latest", 21 | "connect-route": "latest", 22 | "shelljs": "latest" 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /example/src/modules/module1/testACtrl.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 需要外部传入的app, 则`module.exports`为function 3 | */ 4 | define(function (require, exports, module) { 5 | 'use strict'; 6 | 7 | module.exports = function(app){ 8 | //Step6: use `app.register` to register controller/service/directive/filter 9 | app.register.controller('testACtrl', ['$scope', '$routeParams', '$location', '$http', 10 | function($scope, $routeParams, $location, $http){ 11 | //获取页面的入参 12 | var id = $routeParams.id; 13 | $http.get('data/testA.json').then(function(res){ 14 | $scope.dataObj = res; 15 | }, function(res){ 16 | console.log('err', res) 17 | }); 18 | }] 19 | ); 20 | 21 | //注册directive,简单的渲染HTML 22 | app.register.directive('articleContent', function(){ 23 | return function(scope, element, attr) { 24 | element.addClass('ng-binding').data('$binding', attr.articleContent); 25 | scope.$watch(attr.articleContent, function(value) { 26 | element.html(value || ''); 27 | }); 28 | }; 29 | }) 30 | } 31 | }); -------------------------------------------------------------------------------- /dist/angular-lazyload.min.js: -------------------------------------------------------------------------------- 1 | /*! angular-lazyload - v0.4.0 - https://github.com/atian25/angular-lazyload - 2013-10-28 */ 2 | !function(){"use strict";function a(a,c,d){b(a),this.register=d,this.init=function(b,e){var f=angular.isObject(e)?e:this.loaders[e]||this.loaders.seajs;a.$on("$routeChangeStart",function(e,g){var h=g&&g.$$route;h&&(!angular.isFunction(f.check)||f.check(h))&&(h.resolve=h.resolve||{},h.resolve.loadedModule=function(){var e=c.defer();return f.load(h,function(c){a.safeApply(function(){e.resolve(angular.isFunction(c)?c(b,d):c)})},function(b){a.safeApply(function(){e.reject(b)})}),e.promise})})}}function b(a){a.safeApply=function(a){var b=this.$root.$$phase;"$apply"==b||"$digest"==b?a&&"function"==typeof a&&a():this.$apply(a)}}angular.module("angular-lazyload",[],["$controllerProvider","$compileProvider","$filterProvider","$provide",function(b,c,d,e){e.factory("$lazyload",["$rootScope","$q",function(f,g){var h={controller:b.register,directive:c.directive,filter:d.register,factory:e.factory,service:e.service,decorator:e.decorator};return new a(f,g,h)}])}]),a.prototype.loaders={},a.prototype.loaders.seajs={check:function(a){return"string"==typeof a.controllerUrl},load:function(a,b,c){seajs.use(a.controllerUrl,function(a){angular.isUndefined(a)?c(a):b(a)})}},a.prototype.loaders.requirejs={check:function(a){return"string"==typeof a.controllerUrl},load:function(a,b,c){require(a.controllerUrl,function(a){angular.isUndefined(a)?c(a):b(a)})}}}(this); -------------------------------------------------------------------------------- /example/src/app.js: -------------------------------------------------------------------------------- 1 | define(function (require, exports, module) { 2 | "use strict"; 3 | console.log('init app...' + (new Date().getTime())); 4 | 5 | //Step3: add 'angular-lazyload' to your main module's list of dependencies 6 | var app = angular.module('app', ['angular-lazyload', 'ngRoute']); 7 | require('./sharedService.js')(app); 8 | 9 | //配置期 10 | app.config(['$routeProvider', function($routeProvider) { 11 | //Step4: add `controllerUrl` to your route item config 12 | $routeProvider 13 | .when('/test/a', { 14 | controller: 'testACtrl', 15 | controllerUrl: 'modules/module1/testACtrl.js', 16 | templateUrl: 'modules/module1/testA.tpl.html' 17 | }) 18 | .when('/test/b/:id', { 19 | controller: 'testBCtrl', 20 | controllerUrl: 'modules/module2/testBCtrl.js', 21 | templateUrl: 'modules/module2/testB.tpl.html' 22 | }) 23 | .when('/main', { 24 | controller: function($scope, $routeParams, $location){ 25 | $scope.str = new Date() 26 | //console.log($routeParams,$location) 27 | }, 28 | template: '
{{str}}
' 29 | }) 30 | .otherwise({ 31 | redirectTo: '/main' 32 | }); 33 | } 34 | ]); 35 | 36 | //运行期 37 | app.run(['$lazyload', 'sharedService', function($lazyload, sharedService){ 38 | //Step5: init lazyload & hold refs 39 | $lazyload.init(app); 40 | app.register = $lazyload.register; 41 | sharedService.test() 42 | }]); 43 | 44 | module.exports = app; 45 | }); -------------------------------------------------------------------------------- /example/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | angular-lazyload-showcase 6 | 7 | 8 | 9 |

A lazyload service for angular projects, only load-on-demand, support seajs/requirejs/custom.

10 |
11 | main | testA | testB 12 |
13 | 14 |
15 | 16 | 17 | 18 | 19 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # angular-lazyload 2 | 3 | ## **NOT CURRENTLY MAINTAINED, use [ocLazyLoad](https://github.com/ocombe/ocLazyLoad) or angular2** 4 | 5 | #### a lazyload service for angular projects, only load-on-demand, support seajs/requirejs/custom. 6 | ### 按需加载[AngularJS](http://angularjs.org)模块, 支持[Sea.js](http://seajs.org/)和[RequireJS](http://requirejs.org/‎)。 7 | 8 | --- 9 | **[下载](dist/angular-lazyload.js)** (or **[压缩版](dist/angular-lazyload.min.js)**) **|** 10 | **[使用指南](#使用指南) |** 11 | **[基本原理](#基本原理) |** 12 | **[TODO/贡献代码](#TODO) |** 13 | **[示例使用说明](#示例使用说明)** 14 | 15 | --- 16 | 17 | 18 | ### 使用指南 19 | 20 | **(1)** 安装 21 | - 通过[Bower](http://bower.io/)安装: `bower install angular-lazyload` 22 | - 直接下载: [Download](dist/angular-lazyload.js) (or [Minified](dist/angular-lazyload.min.js)) 23 | 24 | **(2)** 在你的`index.html`中引入`angular-lazyload`。 25 | ``` 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | ``` 34 | 35 | **(3)** 在你的启动文件里面, 手动启动bootstrap。 36 | ``` 37 | //Step2: bootstrap youself 38 | seajs.use(['app'], function(app){ 39 | angular.bootstrap(document, ['app']); 40 | }); 41 | ``` 42 | 43 | **(3)** 添加`angular-lazyload`为你的主模块的依赖中。 44 | ``` 45 | //Step3: add 'angular-lazyload' to your main module's list of dependencies 46 | var app = angular.module('app', ['angular-lazyload', 'ngRoute']); 47 | ``` 48 | 49 | **(4)** 在`app.run`里进行初始化。 50 | ``` 51 | app.run(['$lazyload', function($lazyload){ 52 | //Step5: init lazyload & hold refs 53 | $lazyload.init(app); 54 | app.register = $lazyload.register; 55 | }]); 56 | ``` 57 | 58 | **(5)** 路由映射, 添加`controllerUrl` 59 | ``` 60 | //Step4: add `controllerUrl` to your route item config 61 | $routeProvider 62 | .when('/test/a', { 63 | controller: 'testACtrl', 64 | controllerUrl: 'modules/module1/testACtrl.js', 65 | templateUrl: 'modules/module1/testA.tpl.html' 66 | }) 67 | } 68 | ``` 69 | 70 | **(6)** 在你的模块里进行注册controller。 71 | ``` 72 | //Step6: use `app.register` to register controller/service/directive/filter 73 | app.register.controller('testACtrl', ['$scope', function($scope){ 74 | ... 75 | }]); 76 | ``` 77 | 78 | 79 | ### 基本原理 80 | 81 | - 通过`route`的`resolve`做hack点 82 | - 在`config`期保存`register`的引用 83 | - 监听`$routeChangeStart`事件, 动态添加一个`resolve` 84 | - `resolve`里面通过seajs去动态加载模块,并动态注册 85 | 86 | ### TODO 87 | - 添加测试的示例, 参考https://github.com/seajs/seajs/issues/874 88 | - 欢迎PullRequest贡献代码 89 | 90 | ### 示例使用说明 91 | 92 | 1. 安装[nodejs](http://nodejs.org) -- 下载对应版本并安装 93 | 2. 安装[grunt](http://gruntjs.com) -- 命令行下执行: `npm install -g grunt-cli` (不包含符号` ,下同) 94 | 3. 安装[bower](https://github.com/bower/bower) -- 命令行下执行: `npm install -g bower` (不包含符号` ,下同) 95 | 4. 安装依赖库 -- 命令行到项目根目录,执行 `npm install` 96 | 5. 安装Web类库 -- 命令行到**example**目录,执行 `bower install` 97 | 6. 运行示例 -- 命令行执行 `grunt server`, 将自动打开浏览器显示首页 98 | 7. 若参与开发则 -- 命令行执行 `grunt dev`, 欢迎通过PullRequest贡献代码 99 | 100 | 101 | -------------------------------------------------------------------------------- /Gruntfile.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 自动化脚本定义 3 | */ 4 | module.exports = function (grunt) { 5 | 'use strict'; 6 | 7 | //load all grunt tasks 8 | require('matchdep').filterDev('grunt-*').forEach(grunt.loadNpmTasks); 9 | require('shelljs/global'); 10 | var path = require('path'); 11 | 12 | //define tasks 13 | //启动Web服务器,监控变更,自动加载 14 | grunt.registerTask('server', ['connect', 'open', 'watch:server']); 15 | grunt.registerTask('dev', ['connect', 'open', 'watch:dev']); 16 | grunt.registerTask('build', ['clean', 'concat', 'uglify']); 17 | 18 | 19 | //读取配置 20 | var pkg = grunt.file.readJSON('package.json'); 21 | var cfg = { 22 | pkg: pkg, 23 | src: './', 24 | // Change 'localhost' to '0.0.0.0' to access the server from outside. 25 | serverHost: '0.0.0.0', 26 | serverPort: 9000, 27 | serverUrl: 'http://localhost:9000/example/src/index.html', 28 | livereload: 35729 29 | }; 30 | 31 | //grunt config 32 | grunt.initConfig({ 33 | //======== 配置相关 ======== 34 | cfg: cfg, 35 | 36 | //======== 开发相关 ======== 37 | //开启服务 38 | connect: { 39 | options: { 40 | port: cfg.serverPort, 41 | hostname: cfg.serverHost, 42 | middleware: function(connect, options) { 43 | return [ 44 | require('connect-livereload')({ 45 | port: cfg.livereload 46 | }), 47 | connect.query(), 48 | // Serve static files. 49 | connect.static(options.base), 50 | // Make empty directories browsable. 51 | connect.directory(options.base), 52 | ]; 53 | } 54 | }, 55 | server: { 56 | options: { 57 | base: cfg.src 58 | } 59 | } 60 | }, 61 | 62 | //监控文件变化 63 | watch: { 64 | options: { 65 | livereload: cfg.livereload, 66 | }, 67 | server: { 68 | files: [ 69 | cfg.src + '/**' 70 | ], 71 | tasks: [] 72 | }, 73 | dev: { 74 | files: [ 75 | cfg.src + '/**', 76 | '!dist/**' 77 | ], 78 | tasks: ['build'] 79 | } 80 | }, 81 | 82 | //清理 83 | clean: { 84 | build: ['dist/*'] 85 | }, 86 | 87 | //复制 88 | concat: { 89 | options: { 90 | banner: '/*! <%= cfg.pkg.name %> - v<%= cfg.pkg.version %> - <%= cfg.pkg.repository.url %> - <%= grunt.template.today("yyyy-mm-dd") %> */\n' 91 | }, 92 | build: { 93 | files: [ 94 | {expand: true, cwd:'src/', src: ['angular-lazyload.js'], dest: 'dist/'} 95 | ] 96 | } 97 | }, 98 | 99 | //压缩 100 | uglify: { 101 | options: { 102 | banner: '/*! <%= cfg.pkg.name %> - v<%= cfg.pkg.version %> - <%= cfg.pkg.repository.url %> - <%= grunt.template.today("yyyy-mm-dd") %> */\n', 103 | mangle: { 104 | except: ['require','exports', 'module'] 105 | } 106 | }, 107 | build: { 108 | files: { 109 | 'dist/angular-lazyload.min.js' : ['dist/angular-lazyload.js'] 110 | } 111 | } 112 | } 113 | }); 114 | 115 | /** 116 | * 在跨域chrome中打开首页 117 | */ 118 | grunt.registerTask('open', function(crossdomain) { 119 | var url = cfg.serverUrl || 'http://localhost:' + cfg.serverPort; 120 | url = url && url.replace(/"/g, '\\\"') || 'about:blank'; 121 | var param = !crossdomain ? '' : ' --user-data-dir=C:/CHROME_DEV --disable-web-security --allow-file-access-from-files '; 122 | var cmd = 'start chrome '+ url + ' ' + param; 123 | exec(cmd); 124 | }); 125 | }; 126 | -------------------------------------------------------------------------------- /src/angular-lazyload.js: -------------------------------------------------------------------------------- 1 | /** 2 | * A lazyload service for angular projects, only load-on-demand, support seajs/requirejs/custom. 3 | * support [Sea.js](http://seajs.org/) & [RequireJS](http://requirejs.org/‎) 4 | * 5 | * @author TZ 6 | * @home https://github.com/atian25/angular-lazyload 7 | */ 8 | (function(global, undefined) { 9 | 'use strict'; 10 | 11 | /** 12 | * register `angular-lazyload` module & `$lazyload` service 13 | */ 14 | angular.module('angular-lazyload', [], ['$controllerProvider', '$compileProvider', '$filterProvider', '$provide', 15 | function ($controllerProvider, $compileProvider, $filterProvider, $provide) { 16 | //register `$lazyload` service 17 | $provide.factory('$lazyload', ['$rootScope', '$q', function($rootScope, $q){ 18 | //hold provide's refs, because after ng bootstrap, you can't use `app.controller` to dynamic register controller. 19 | var register = { 20 | controller: $controllerProvider.register, 21 | directive: $compileProvider.directive, 22 | filter: $filterProvider.register, 23 | factory: $provide.factory, 24 | service: $provide.service, 25 | decorator: $provide.decorator 26 | }; 27 | return new LazyLoadProvider($rootScope, $q, register); 28 | }]); 29 | } 30 | ]); 31 | 32 | /** 33 | * $lazyload Service 34 | */ 35 | function LazyLoadProvider($rootScope, $q, register){ 36 | //patch the $rootScope, add `safeApply` function. 37 | patchScope($rootScope); 38 | 39 | /** 40 | * hold provide's refs, because after ng bootstrap, you can't use `app.controller` to dynamic register controller. 41 | */ 42 | this.register = register; 43 | 44 | /** 45 | * @param {Object} params This will pass to the lazy load module 46 | * @param {String} eventName Default to `$routeChangeStart`, //TODO: support `ui-route` 47 | * @param {Function/String} loaderType The loader function: //FIXME: only support `seajs` current. 48 | * - 'seajs' : default value, use [Sea.js](http://seajs.org/) to async load modules 49 | * - 'requirejs': use [RequireJS](http://requirejs.org/‎) to async load modules 50 | * - {Object} : custom loader: 51 | * - check {Function} Optional , check whether need to load by loader 52 | * - load {Function} 53 | * - route : current route item 54 | * - register: register refs object 55 | * - callback : callback function when async load success 56 | */ 57 | this.init = function(params, loaderType){ 58 | //get loaderFn: if loaderType is function, then just use it, else use build in loader by loaderType, default to seajs 59 | var loader = angular.isObject(loaderType) ? loaderType : this.loaders[loaderType] || this.loaders['seajs']; 60 | 61 | //listen to route change event to hook 62 | $rootScope.$on('$routeChangeStart', function(e, target){ 63 | //console.debug(e, '|', target); 64 | var route = target && target.$$route; 65 | if(route){ 66 | // if loader provide check(), then check it 67 | if(!angular.isFunction(loader.check) || loader.check(route)){ 68 | route.resolve = route.resolve || {}; 69 | //keypoint: use `route.resolve` 70 | route.resolve.loadedModule = function(){ 71 | var defer = $q.defer(); 72 | loader.load(route, function(m){ 73 | $rootScope.safeApply(function(){ 74 | defer.resolve(angular.isFunction(m) ? m(params, register) : m); 75 | }); 76 | }, function(m){ 77 | $rootScope.safeApply(function(){ 78 | defer.reject(m); 79 | }); 80 | }); 81 | return defer.promise; 82 | } 83 | } 84 | } 85 | }); 86 | } 87 | } 88 | 89 | /** 90 | * build-in loaders 91 | */ 92 | LazyLoadProvider.prototype.loaders = {}; 93 | 94 | LazyLoadProvider.prototype.loaders['seajs'] = { 95 | check: function(route){ 96 | //if exsit `controllerUrl` then trigger seajs async load. 97 | return typeof route.controllerUrl == 'string' 98 | }, 99 | load: function(route, suc, fail){ 100 | seajs.use(route.controllerUrl, function(m){ 101 | if(angular.isUndefined(m)){ 102 | fail(m); 103 | }else{ 104 | suc(m); 105 | } 106 | }); 107 | } 108 | } 109 | 110 | LazyLoadProvider.prototype.loaders['requirejs'] = { 111 | check: function(route){ 112 | //if exsit `controllerUrl` then trigger requirejs async load. 113 | return typeof route.controllerUrl == 'string' 114 | }, 115 | load: function(route, suc, fail){ 116 | require(route.controllerUrl, function(m){ 117 | if(angular.isUndefined(m)){ 118 | fail(m); 119 | }else{ 120 | suc(m); 121 | } 122 | }); 123 | } 124 | } 125 | 126 | /** 127 | * 为$rootScope增加safeApply方法, 安全的apply 128 | */ 129 | function patchScope($rootScope){ 130 | $rootScope.safeApply = function(fn){ 131 | var phase = this.$root.$$phase; 132 | if(phase == '$apply' || phase == '$digest') { 133 | if(fn && (typeof(fn) === 'function')) { 134 | fn(); 135 | } 136 | } else { 137 | this.$apply(fn); 138 | } 139 | }; 140 | } 141 | })(this); -------------------------------------------------------------------------------- /dist/angular-lazyload.js: -------------------------------------------------------------------------------- 1 | /*! angular-lazyload - v0.4.0 - https://github.com/atian25/angular-lazyload - 2013-10-28 */ 2 | /** 3 | * A lazyload service for angular projects, only load-on-demand, support seajs/requirejs/custom. 4 | * support [Sea.js](http://seajs.org/) & [RequireJS](http://requirejs.org/‎) 5 | * 6 | * @author TZ 7 | * @home https://github.com/atian25/angular-lazyload 8 | */ 9 | (function(global, undefined) { 10 | 'use strict'; 11 | 12 | /** 13 | * register `angular-lazyload` module & `$lazyload` service 14 | */ 15 | angular.module('angular-lazyload', [], ['$controllerProvider', '$compileProvider', '$filterProvider', '$provide', 16 | function ($controllerProvider, $compileProvider, $filterProvider, $provide) { 17 | //register `$lazyload` service 18 | $provide.factory('$lazyload', ['$rootScope', '$q', function($rootScope, $q){ 19 | //hold provide's refs, because after ng bootstrap, you can't use `app.controller` to dynamic register controller. 20 | var register = { 21 | controller: $controllerProvider.register, 22 | directive: $compileProvider.directive, 23 | filter: $filterProvider.register, 24 | factory: $provide.factory, 25 | service: $provide.service, 26 | decorator: $provide.decorator 27 | }; 28 | return new LazyLoadProvider($rootScope, $q, register); 29 | }]); 30 | } 31 | ]); 32 | 33 | /** 34 | * $lazyload Service 35 | */ 36 | function LazyLoadProvider($rootScope, $q, register){ 37 | //patch the $rootScope, add `safeApply` function. 38 | patchScope($rootScope); 39 | 40 | /** 41 | * hold provide's refs, because after ng bootstrap, you can't use `app.controller` to dynamic register controller. 42 | */ 43 | this.register = register; 44 | 45 | /** 46 | * @param {Object} params This will pass to the lazy load module 47 | * @param {String} eventName Default to `$routeChangeStart`, //TODO: support `ui-route` 48 | * @param {Function/String} loaderType The loader function: //FIXME: only support `seajs` current. 49 | * - 'seajs' : default value, use [Sea.js](http://seajs.org/) to async load modules 50 | * - 'requirejs': use [RequireJS](http://requirejs.org/‎) to async load modules 51 | * - {Object} : custom loader: 52 | * - check {Function} Optional , check whether need to load by loader 53 | * - load {Function} 54 | * - route : current route item 55 | * - register: register refs object 56 | * - callback : callback function when async load success 57 | */ 58 | this.init = function(params, loaderType){ 59 | //get loaderFn: if loaderType is function, then just use it, else use build in loader by loaderType, default to seajs 60 | var loader = angular.isObject(loaderType) ? loaderType : this.loaders[loaderType] || this.loaders['seajs']; 61 | 62 | //listen to route change event to hook 63 | $rootScope.$on('$routeChangeStart', function(e, target){ 64 | //console.debug(e, '|', target); 65 | var route = target && target.$$route; 66 | if(route){ 67 | // if loader provide check(), then check it 68 | if(!angular.isFunction(loader.check) || loader.check(route)){ 69 | route.resolve = route.resolve || {}; 70 | //keypoint: use `route.resolve` 71 | route.resolve.loadedModule = function(){ 72 | var defer = $q.defer(); 73 | loader.load(route, function(m){ 74 | $rootScope.safeApply(function(){ 75 | defer.resolve(angular.isFunction(m) ? m(params, register) : m); 76 | }); 77 | }, function(m){ 78 | $rootScope.safeApply(function(){ 79 | defer.reject(m); 80 | }); 81 | }); 82 | return defer.promise; 83 | } 84 | } 85 | } 86 | }); 87 | } 88 | } 89 | 90 | /** 91 | * build-in loaders 92 | */ 93 | LazyLoadProvider.prototype.loaders = {}; 94 | 95 | LazyLoadProvider.prototype.loaders['seajs'] = { 96 | check: function(route){ 97 | //if exsit `controllerUrl` then trigger seajs async load. 98 | return typeof route.controllerUrl == 'string' 99 | }, 100 | load: function(route, suc, fail){ 101 | seajs.use(route.controllerUrl, function(m){ 102 | if(angular.isUndefined(m)){ 103 | fail(m); 104 | }else{ 105 | suc(m); 106 | } 107 | }); 108 | } 109 | } 110 | 111 | LazyLoadProvider.prototype.loaders['requirejs'] = { 112 | check: function(route){ 113 | //if exsit `controllerUrl` then trigger requirejs async load. 114 | return typeof route.controllerUrl == 'string' 115 | }, 116 | load: function(route, suc, fail){ 117 | require(route.controllerUrl, function(m){ 118 | if(angular.isUndefined(m)){ 119 | fail(m); 120 | }else{ 121 | suc(m); 122 | } 123 | }); 124 | } 125 | } 126 | 127 | /** 128 | * 为$rootScope增加safeApply方法, 安全的apply 129 | */ 130 | function patchScope($rootScope){ 131 | $rootScope.safeApply = function(fn){ 132 | var phase = this.$root.$$phase; 133 | if(phase == '$apply' || phase == '$digest') { 134 | if(fn && (typeof(fn) === 'function')) { 135 | fn(); 136 | } 137 | } else { 138 | this.$apply(fn); 139 | } 140 | }; 141 | } 142 | })(this); --------------------------------------------------------------------------------