角UI的路由器requirejs,控制器的延迟加载 [英] angular-ui-router with requirejs, lazy loading of controller

查看:126
本文介绍了角UI的路由器requirejs,控制器的延迟加载的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

你能帮助我了解如何在示例中的视图之前加载下面控制器?它看起来像的观点只是立即加载同时控制器还没有加载。

  // app.js
$ stateProvider.state('指数',{
    网址:/,
    观点:{
        顶部菜单:{
            templateUrl:/首页/顶部菜单
            控制器:函数($范围,$喷油器){
                需要(['控制器/顶菜单控制器'],功能(模块){
                    $ injector.invoke(模块,为此,{'$范围:$范围});
                });
            }
        }
    }
});//top-menu-controller.js
定义(['应用'],功能(应用程序){
    app.controller('TopMenuCtrl',['$范围',函数($范围){
        $ scope.message =它的工作原理;
    }]);
});//主页/顶部菜单
< H3>顶部菜单和LT; / H3 GT&;
< D​​IV NG控制器=TopMenuCtrl>
    {{信息}}
< / DIV>


解决方案

工作plunker 在这里。

让我们这样的 index.html的的:

 <!DOCTYPE HTML>
< HTML和GT;
  < HEAD>
    <标题>我懒< /标题>
  < /头>  <机身NG-应用=应用程序>      < A HREF =#/家>#/家< / A> //我们有三种状态 - 家更是不可以偷懒
      &所述; A HREF =#/>#/&下; / A> - 指数//索引很懒,有两种观点
      < A HREF =#/其他>#/其它< / A> //'其他'是懒惰的未命名视图    < D​​IV数据的用户界面视图=顶部菜单>< / DIV>
    < D​​IV数据的用户界面视图=>< / DIV>    &所述; SCRIPT SRC =angular.js>&下; /脚本> //标准角
    <脚本SRC =角-UI-router.js>< / SCRIPT> //和UI路由器scritps    &所述; SCRIPT SRC =的script.js>&下; /脚本> //我们的应用程序    <脚本数据主要=main.js//懒惰依赖
        SRC =require.js>&下; /脚本>  < /身体GT;
< / HTML>

让我们来观察 main.js - 在RequireJS配置:

  require.config({    //的baseUrl:JS /脚本
    的baseUrl:,    //别名库的路径
    路径:{        //这里我们定义路径名字
        //使控制器和他们的懒惰的文件名独立        TopMenuCtrl:Controller_TopMenu,
        ContentCtrl:Controller_Content,
        OtherCtrl:Controller_Other,
    },    DEPS:['应用']
});

事实上,我们只为我们的 ControllerNames 别名(路径) - 和他们的 Controller_Scripts.js 文件。而已。的此外,我们返回到需要的应用程序,但是我们将在以后的情况下使用不同的功能 - 注册延迟加载控制器

什么是的 DEPS:['应用'] 是什么意思?首先,我们需要提供文件的 app.js (以下简称程序是指找到 app.js

 定义([],函数(){  VAR应用= angular.module(应用);
  返回程序;
})

这返回的值是一个我们可以要求在每一个异步加载的文件

 定义(['应用'],功能(应用程序){
    //这里我们将有机会获得该模块(应用程序)
});

我们将如何负载控制器懒洋洋地?这里已经被证明为 ngRoute

angularAMD v0.2.1


  

angularAMD是助益AngularJS应用支持按需加载第三方模块,如角UI的使用RequireJS的效用。


我们会问角的提及<一个href=\"https://docs.angularjs.org/api/ng/provider/$controllerProvider#register\"><$c$c>$controllerProvider - 后来使用它来注册控制器

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

  //一,申请
VAR应用= angular.module(应用,[
  ui.router
]);
// II。缓存$ controllerProvider
变种app_cached_providers = {};的app.config(['$ controllerProvider',
  功能(controllerProvider){
    app_cached_providers $ controllerProvider = controllerProvider。
  }
]);

我们可以看到,我们刚创建的​​应用程序应用程序,也,创造了持有人的 app_cached_providers (继angularAMD风格)的。在配置阶段,我们要求对角<一个href=\"https://docs.angularjs.org/api/ng/provider/$controllerProvider#register\"><$c$c>$controllerProvider并保持引用它。

现在,让我们继续的的script.js 的:

  // III。内嵌依赖前pression
的app.config(['$ stateProvider','$ urlRouterProvider',
  功能($ stateProvider,$ urlRouterProvider){    $ urlRouterProvider
      不然的话(/家庭);    $ stateProvider
      .STATE(家,{
        网址:/家,
        模板:&LT; D​​IV&gt;这是家 - 而不是延迟加载&LT; / DIV&gt;中
      });    $ stateProvider
      .STATE(其他,{
        网址:/等,
        模板:&LT; D​​IV&GT;从CTRL消息:{{}信息}&LT; / DIV&gt;中,
        控制器:OtherCtrl
        解析:{
          loadOtherCtrl:[$ Q功能($ Q){
            变种推迟= $ q.defer();
            需要([OtherCtrl],函数(){deferred.resolve();});
            返回deferred.promise;
          }],
        },
      });  }
]);

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

二是国家命名为其他这确实目标未命名视图用户界面视图=。在这里,我们可以看到首先,延迟加载。在的解析 (参见:)

解决


  

您可以使用决心提供内容或数据的控制器,自定义的状态。解析是依赖的可选地图应该被注射到所述控制器


  
  

如果这些依赖关系都承诺后,他们的将得到解决和控制器进行实例化之前和$ stateChangeSuccess事件被激发转换成一个值。


使用,在我们的套件,我们知道,该控制器(通过其名称)将在角资料库中搜索,一旦决心完成:

  //此控制器名进行搜索 - 只有一次决心完成
控制器:OtherCtrl
//让我们问RequireJS
解析:{
  loadOtherCtrl:[$ Q功能($ Q){
    //凌晨需要$ Q等待
    变种推迟= $ q.defer();
    //并使其得到解决,一旦需要将加载文件
    需要([OtherCtrl],函数(){deferred.resolve();});
    返回deferred.promise;
  }],
},

好,现在,如上述提到的,主要包含此别名DEF

  //别名库的路径
路径:{
    ...
    OtherCtrl:Controller_Other,

这意味着,该文件Controller_Other.js将搜索和加载。这是它的内容,它执行魔术。这里最重要的是使用$ P $的pviously缓存参考<一个href=\"https://docs.angularjs.org/api/ng/provider/$controllerProvider#register\"><$c$c>$controllerProvider

  //内容的Controller_Other.js的定义(['应用'],功能(应用程序){
    //默认的控制器
    //加入到应用程序模块
    //懒洋洋地,只有一次
    app_cached_providers
      。$ controllerProvider
      .register('OtherCtrl',函数($范围){
        $ scope.message =OtherCtrl;
    });
});

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

<$c$c>$controllerProvider.Register


  

在$控制服务由角来创建新的控制器。此提供程序允许控制器通过注册在 寄存器() 方式。


最后,还有另一种状态定义,更缩小了决心......一试,使其更易于阅读:

  // IV ...建立与辅助功能对象
//然后将分配给国家提供
VAR loadController =功能(controllerName){
  返回[$ Q功能($ Q){
      变种推迟= $ q.defer();
      需要([controllerName]功能(){deferred.resolve();});
      返回deferred.promise;
  }];
}的app.config(['$ stateProvider','$ urlRouterProvider',
  功能($ stateProvider,$ urlRouterProvider){    VAR指数= {
        网址:/,
        观点:{
          顶部菜单:{
            模板:&LT; D​​IV&GT;从CTRL消息:{{}信息}&LT; / DIV&gt;中,
            控制器:TopMenuCtrl
          },
          :{
            模板:&LT; D​​IV&GT;从CTRL消息:{{}信息}&LT; / DIV&gt;中,
            控制器:ContentCtrl
          },
        },
        解决:{},
    };
    index.resolve.loadTopMenuCtrl = loadController(TopMenuCtrl);
    index.resolve.loadContentCtrl = loadController(ContentCtrl);    $ stateProvider
      .STATE(指数,指数);
}]);

以上我们可以看到,我们解决两个控制器为/该国的所有命名视图

就是这样。这里定义每个控制器

 路径:{
    TopMenuCtrl:Controller_TopMenu,
    ContentCtrl:Controller_Content,
    OtherCtrl:Controller_Other,
    ...
},

通过RequireJS - - 懒洋洋地

将通过决心和 $ controllerProvider 加载。检查所有的这里

类似的问答集答: AngularAMD + UI路由器+动态控制器名称

Could you help me to understand how to load controller in the example below before the view? It looks like the view is loaded just immediately while the controller is not loaded yet.

//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>

解决方案

I created working plunker here.

Let's have this index.html:

<!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>

Let's observe the main.js - the RequireJS config:

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']
});

In fact, we only create aliases (paths) for our ControllerNames - and their Controller_Scripts.js files. That's it. Also, we return to require the app, but we will in our case use different feature later - to register lazily loaded controllers.

what does the deps: ['app'] mean? Firstly, we need to provide file app.js (the 'app' means find app.js) :

define([], function() {

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

this returned value is the one we can ask for in every async loaded file

define(['app'], function (app) {
    // here we would have access to the module("app")
});

How will we load controllers lazily? As already proven here for ngRoute

angularAMD v0.2.1

angularAMD is an utility that facilitates the use of RequireJS in AngularJS applications supporting on-demand loading of 3rd party modules such as angular-ui.

We will ask angular for a reference to $controllerProvider - and use it later, to register controllers.

This is the first part of our script.js:

// 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;
  }
]);

As we can see, we just created the application 'app' and also, created holder app_cached_providers (following the angularAMD style). In the config phase, we ask angular for $controllerProvider and keep reference for it.

Now let's continue in script.js:

// 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;
          }],
        },
      });

  }
]);

This part above shows two states declaration. One of them - 'home' is standard none lazy one. It's controller is implicit, but standard could be used.

The second is state named "other" which does target unnamed view ui-view="". And here we can firstly see, the lazy load. Inside of the resolve (see:)

Resolve

You can use resolve to provide your controller with content or data that is custom to the state. resolve is an optional map of dependencies which should be injected into the controller.

If any of these dependencies are promises, they will be resolved and converted to a value before the controller is instantiated and the $stateChangeSuccess event is fired.

With that in our suite, we know, that the controller (by its name) will be searched in angular repository once the resolve is finished:

// 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;
  }],
},

Good, now, as mentioned above, the main contains this alias def

// alias libraries paths
paths: {       
    ...
    "OtherCtrl"  : "Controller_Other",

And that means, that the file "Controller_Other.js" will be searched and loaded. This is its content which does the magic. The most important here is use of previously cached reference to $controllerProvider

// 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";
    });        
});

the trick is not to use app.controller() but

$controllerProvider.Register

The $controller service is used by Angular to create new controllers. This provider allows controller registration via the register() method.

Finally there is another state definition, with more narrowed resolve... a try to make it more readable:

// 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);          
}]);

Above we can see, that we resolve two controllers for both/all named views of that state

That's it. Each controller defined here

paths: { 
    "TopMenuCtrl": "Controller_TopMenu",
    "ContentCtrl": "Controller_Content",
    "OtherCtrl"  : "Controller_Other",
    ...
},

will be loaded via resolve and $controllerProvider - via RequireJS - lazily. Check that all here

Similar Q & A: AngularAMD + ui-router + dynamic controller name?

这篇关于角UI的路由器requirejs,控制器的延迟加载的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆