使用Angular UI路由器动态加载控制器

时间:2014-01-21 01:11:13

标签: angularjs angular-ui-router

我在一个拥有数十个模板的应用中使用ui-router。每个模板都有一个控制器。

从我一直在阅读的内容来看,这样的事情(设置路线)应该有效:

.config(function($stateProvider, $urlRouterProvider) {
  $stateProvider
    .state('start', {
      url: '/start',
      templateUrl: 'partials/start.html',
      controller: 'StartCtrl'
    })
});

这是假设之前定义的StartCtrl。该应用程序最终将拥有数十个控制器,并且不希望一次性下载所有控制器的开销。如何仅在请求模板时加载控制器?

2 个答案:

答案 0 :(得分:4)

我为此使用RequireJS。还有一个提供者,比如lazyProvider:

在懒惰的提供者中......

this.resolve = function(controller){
    return { myCtrl: ['$q',function ($q){
            var defer = $q.defer();
            require(['/app/controllers/'+controller,'myApp'],function(ctrl,myApp){
                myApp.register.controller(controller,ctrl);
                defer.resolve();

            }
            return defer.promise;
        }]
    };
};

在您的ui-router resolve:属性中执行:

resolve: lazyProvider.resolve('myCtrl');

您需要在应用上公开提供商注册表,以便稍后注册,例如:

myApp.config(function($urlRouterProvider, $stateProvider,
          $controllerProvider, $compileProvider, $filterProvider,$provide){
    //If your myApp isn't already a module...
    define('myApp',[],function(){return myApp});
    myApp.register = {
        controller: $controllerProvider.register,
        directive: $compileProvider.directive,
        filter: $filterProvider.register,
        factory: $provide.factory,
        service: $provide.service,
        constant: $provide.constant
    }

你的控制员:

define(['/dependencies'],function(deps){
    function MyCtrl($scope){...}
    return MyCtrl;
}

这实际上是Dan Wahlin分享的here

答案 1 :(得分:1)

在使用@calebboyd示例后,我使用System.js和ES6进行了工作。我喜欢这个实现的是,使用ES6模块,一切都只取决于已经唯一的文件名,因此您不需要关心控制器名称冲突甚至命名它们。控制器是匿名的。

此实现假设您有一个文件夹“pages”,其中包含模板/控制器对,如下所示:

/pages
  /page1.html
  /page1.js
  /page2.html
  /page2.js

访问/#pages/page1后,它将动态加载模板和控制器。

这是你的“app.js”:

import angular from 'angular';
import 'angular-ui-router';

angular.module('app', ['ui.router'])
  .config(($stateProvider, $urlRouterProvider, $controllerProvider) => {

    // save reference to the register method, so we can use inside the 'resolve'
    var registerController = $controllerProvider.register;

    // register a single state that takes the page name as a parameter
    $stateProvider
      .state('pages', {
        url: "/pages/:name",

        // the url and the controller name are dynamically created
        templateUrl: $stateParams => "pages/" + $stateParams.name + ".html",
        controllerProvider: $stateParams => $stateParams.name + '_DynamicController as vm',

        resolve: {

          'ctrl': ($stateParams, $q) => {

            var script = 'pages/' + $stateParams.name;
            var controllerName = $stateParams.name + '_DynamicController';

            // once System.js loads the module, we register using the
            // saved registerController function with the dynamic name
            return System.import(script)
              .then(ctrl => registerController(controllerName, ctrl['default']));
          }
        }
      });
  });

以下是“page1.js”中的示例控制器:

export default class {
  constructor() {
    this.data = "inside the controller";
  }
}

“page1.html”中的示例模板:

<h1>Page1 Template</h1>
Loaded: {{ vm.data }}