首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >angular-ui-router,要求,延迟加载控制器

angular-ui-router,要求,延迟加载控制器
EN

Stack Overflow用户
提问于 2014-03-25 15:18:34
回答 2查看 13.9K关注 0票数 13

你能帮我理解一下如何在视图之前加载下面示例中的控制器吗?它看起来就像是在控制器还没有加载的时候立即加载视图。

代码语言:javascript
复制
//app.js
$stateProvider.state('index', {
    url: "/",
    views: {
        "topMenu": {
            templateUrl: "/Home/TopMenu",
            controller: function($scope, $injector) {
                require(['controllers/top-menu-controller'], function(module) {
                    $injector.invoke(module, this, { '$scope': $scope });
                });
            }
        }
    }
});

//top-menu-controller.js
define(['app'], function (app) {
    app.controller('TopMenuCtrl', ['$scope', function ($scope) {
        $scope.message = "It works";
    }]);
});

//Home/TopMenu
<h3>TopMenu</h3>
<div ng-controller="TopMenuCtrl">
    {{message}}
</div>
EN

回答 2

Stack Overflow用户

发布于 2015-01-03 18:50:59

I created working plunker here。

让我们使用这个index.html

代码语言:javascript
复制
<!DOCTYPE html>
<html>
  <head>
    <title>my lazy</title>    
  </head>

  <body ng-app="app">
    
      <a href="#/home">#/home</a>     // we have three states - 'home' is NOT lazy
      <a href="#/">#/</a>  - index    // 'index' is lazy, with two views
      <a href="#/other">#/other</a>   // 'other' is lazy with unnamed view
    
    <div data-ui-view="topMenu"></div>        
    <div data-ui-view=""></div>
    
    <script src="angular.js"></script>           // standard angular
    <script src="angular-ui-router.js"></script> // and ui-router scritps

    <script src="script.js"></script>            // our application

    <script data-main="main.js"                  // lazy dependencies
        src="require.js"></script>
     
  </body>    
</html>

让我们观察一下main.js - RequireJS配置:

代码语言:javascript
复制
require.config({

    //baseUrl: "js/scripts",
    baseUrl: "",

    // alias libraries paths
    paths: { 
      
        // here we define path to NAMES
        // to make controllers and their lazy-file-names independent
        
        "TopMenuCtrl": "Controller_TopMenu",
        "ContentCtrl": "Controller_Content",
        "OtherCtrl"  : "Controller_Other",
    },

    deps: ['app']
});

实际上,我们只为ControllerNames及其Controller_Scripts.js文件创建别名(路径)。就这样。此外,我们返回请求应用程序,但我们将在稍后使用不同的功能-注册延迟加载的控制器。

deps: ['app']是什么意思?首先,我们需要提供app.js ( 'app‘的意思是查找app.js__):

代码语言:javascript
复制
define([], function() {

  var app = angular.module('app');
  return app; 
})

此返回值是我们可以在每个异步加载的文件中请求的值

代码语言:javascript
复制
define(['app'], function (app) {
    // here we would have access to the module("app")
});

我们如何懒惰地加载控制器?这里已经为ngRoute证明了这一点

angularAMD v0.2.1

angularAMD是一个实用程序,可促进在支持按需加载第三方模块(如angular-ui )的AngularJS应用程序中使用RequireJS。

我们将向angular请求$controllerProvider的引用--稍后使用它来注册控制器。

这是我们script.js的第一部分

代码语言:javascript
复制
// I. the application
var app = angular.module('app', [
  "ui.router"
]);


// II. cached $controllerProvider
var app_cached_providers = {};

app.config(['$controllerProvider',
  function(controllerProvider) {
    app_cached_providers.$controllerProvider = controllerProvider;
  }
]);

正如我们所看到的,我们刚刚创建了应用程序'app‘,还创建了holder app_cached_providers (遵循angularAMD风格)。在配置阶段,我们向angular请求$controllerProvider并保留它的引用。

现在让我们继续script.js

代码语言:javascript
复制
// III. inline dependency expression
app.config(['$stateProvider', '$urlRouterProvider',
  function($stateProvider, $urlRouterProvider) {

    $urlRouterProvider
      .otherwise("/home");

    $stateProvider
      .state("home", {
        url: "/home",
        template: "<div>this is home - not lazily loaded</div>"
      });

    $stateProvider
      .state("other", {
        url: "/other",
        template: "<div>The message from ctrl: {{message}}</div>",
        controller: "OtherCtrl",
        resolve: {
          loadOtherCtrl: ["$q", function($q) { 
            var deferred = $q.defer();
            require(["OtherCtrl"], function() { deferred.resolve(); });
            return deferred.promise;
          }],
        },
      });

  }
]);

上面的这部分显示了两个状态声明。其中之一- 'home'是标准的,不是懒惰的。它的控制器是隐式的,但可以使用标准。

第二个是以未命名视图ui-view=""为目标的名为"other"的状态。在这里,我们首先可以看到,惰性负载。在resolve内部(请参见:)

Resolve

您可以使用resolve为控制器提供自定义状态的内容或数据。resolve是一个可选的依赖映射,它应该被注入到控制器中。

如果这些依赖项中的任何一个是promises,那么在控制器实例化和触发$stateChangeSuccess事件之前,它们将被解析并转换为一个值。

在我们的套件中,我们知道,一旦解析完成,将在angular存储库中搜索控制器(按其名称):

代码语言:javascript
复制
// this controller name will be searched - only once the resolve is finished
controller: "OtherCtrl",
// let's ask RequireJS
resolve: {
  loadOtherCtrl: ["$q", function($q) { 
    // wee need $q to wait
    var deferred = $q.defer();
    // and make it resolved once require will load the file
    require(["OtherCtrl"], function() { deferred.resolve(); });
    return deferred.promise;
  }],
},

很好,现在,正如上面提到的,main包含这个别名def

代码语言:javascript
复制
// alias libraries paths
paths: {       
    ...
    "OtherCtrl"  : "Controller_Other",

这意味着,将搜索并加载文件"Controller_Other.js“。这就是它的内容,它实现了神奇的。这里最重要的是使用以前缓存的对$controllerProvider的引用

代码语言:javascript
复制
// content of the "Controller_Other.js"

define(['app'], function (app) {
    // the Default Controller
    // is added into the 'app' module
    // lazily, and only once
    app_cached_providers
      .$controllerProvider
      .register('OtherCtrl', function ($scope) {
        $scope.message = "OtherCtrl";
    });        
});

诀窍不是使用app.controller(),而是

$controllerProvider.Register

Angular使用$controller服务来创建新的控制器。此提供程序允许通过register()方法进行控制器注册。

最后还有另一个状态定义,具有更窄的分辨率...试着让它更具可读性:

代码语言:javascript
复制
// IV ... build the object with helper functions
//        then assign to state provider    
var loadController = function(controllerName) {
  return ["$q", function($q) {
      var deferred = $q.defer();
      require([controllerName], function() {deferred.resolve(); });
      return deferred.promise;
  }];
}    

app.config(['$stateProvider', '$urlRouterProvider',
  function($stateProvider, $urlRouterProvider) {

    var index = {
        url: "/",
        views: {
          "topMenu": {
            template: "<div>The message from ctrl: {{message}}</div>",
            controller: "TopMenuCtrl",
          },
          "": {
            template: "<div>The message from ctrl: {{message}}</div>",
            controller: "ContentCtrl",
          },
        },
        resolve : { },
    };        
    index.resolve.loadTopMenuCtrl = loadController("TopMenuCtrl");
    index.resolve.loadContentCtrl = loadController("ContentCtrl");
    
    $stateProvider
      .state("index", index);          
}]);

上面我们可以看到,我们为该状态的两个/所有命名视图解析了两个控制器

就这样。此处定义的每个控制器

代码语言:javascript
复制
paths: { 
    "TopMenuCtrl": "Controller_TopMenu",
    "ContentCtrl": "Controller_Content",
    "OtherCtrl"  : "Controller_Other",
    ...
},

将通过resolve和$controllerProvider -通过RequireJS -延迟加载。检查所有here

类似的问答:AngularAMD + ui-router + dynamic controller name?

票数 13
EN

Stack Overflow用户

发布于 2014-09-09 21:07:41

在一个项目中,我使用了延迟加载控制器,并且必须手动调用作用域上的$digest才能使其正常工作。我猜这个行为不会随着ui-router的变化而改变。你试过了吗?

代码语言:javascript
复制
define(['app'], function (app) {
  app.controller('TopMenuCtrl', ['$scope', function ($scope) {
    $scope.message = "It works";
    $scope.$digest();
  }]);
});
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/22627806

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档