如何使用angular-ui-router在一个请求中加载控制器和模板

时间:2015-06-20 12:01:59

标签: angularjs angular-ui-router lazy-loading

我试图延迟加载组件。该组件是一个带有嵌入式脚本标记的html片段,其中包含控制器。

<script>
    ... controller code .....
</script>
<div>
    ... template ....
</div>

片段是在一个html请求中生成的,所以我不能在状态定义中使用templateUrl AND componentURL。

我尝试使用templateProvider来获取组件,而不是提取函数的脚本代码并使用对controllerProvider的引用来注册它。

我确信必须有一个更好的方法来做到这一点,而不是我提出的丑陋的解决方案。我对controllerpovider进行了全局引用,然后使用getComponent服务通过templateProvide读取组件。接下来,我提取脚本并对其进行评估,并注册控制器。

请参阅plunker了解我尝试解决此问题的方法。

.factory('getComponent', function($http, $q) {
  return function (params) {
    var d = $q.defer();
    // optional parameters
    $http.get('myComponent.html').then(function (html) {
            // the component contains a script tag and the rest of the template.
            // the script tags contain the controller code.
            // first i extract the two parts
            var parser = new window.DOMParser();
            var doc = parser.parseFromString(html.data, 'text/html');
            var script = doc.querySelector('script');
            // Here is my problem. I now need to instantiate and register the controller. 
            // It is now done using an eval which of cours is not the way to go
            eval(script.textContent);
            // return the htm which contains the template
            var html = doc.querySelector('body').innerHTML;
            d.resolve(html);
    });
    return d.promise;
  };
})

也许可以使用templateProvider和controllerProvider来完成,但我不确定如何使用一个http请求解决这两个问题。任何帮助/想法将不胜感激。

1 个答案:

答案 0 :(得分:1)

Here's a working plunkr

  • 您无法在运行时访问$ controllerProvider,因此无法注册命名控制器
    • UI-Router不需要命名/注册的控制器功能。 { controller: function() {} }在州定义中完全有效
    • 但是,如果您需要注册控制器,您可以使用像ocLazyLoad这样的工具进行注册。
  • UI-Router将控制器链接到模板,因此html中不需要ng-controller

这是我如何一起攻击这个。 getController工厂现在保留了“组件承诺”的缓存。我保留了你的eval和模板解析,将响应分成两部分。我用包含ctrl / template的对象解决了promise。

组件工厂

  .factory('getComponent', function($http, $q) {
      var components = {};
      return function (name, params) {
        if (components[name]) 
          return components[name];

        return components[name] = $http.get(name + '.html').then(extractComponent);

        function extractComponent(html) {
          var parser = new window.DOMParser();
          var doc = parser.parseFromString(html.data, 'text/html');
          var script = doc.querySelector('script');
          // returns a function from the <script> tag
          var ctrl = eval(script.textContent);
          // return the htm which contains the template
          var tpl = doc.querySelector('body').innerHTML;
          // resolve the promise with this "component"
          return {ctrl: ctrl, tpl: tpl};
        }
      };
  })

myComponent.html

<script>
  var controller = function($scope) {
    $scope.sayHi = function() {
      alert(' Hi from My controller')
    }
  };
  // This statement is assigned to a variable after the eval()
  controller;
</script>

// No ng-controller
<div>
  Lazyloaded template with controller in one pass.
  <button ng-click="sayHi()">Click me to see that the controller actually works.</button>
</div>

在州定义中:

  • 我创建了一个名为'component'的解决方案。该决定要求getComponent工厂获取名为'myComponent'的组件(提示:'myComponent'可能是路由参数)
  • 当它准备就绪时,解析将暴露给UI-Router状态子树。
  • 状态已激活
  • 视图已初始化
    • 控制器提供程序和模板提供程序注入已解析的component,并将控制器/模板返回到UI-Router。

气味测试

我应该提一下,在一个html文件中获取一个控制器和模板,并手动解析我的气味。

您可以追求的一些变化:

  • 改进getComponent工厂;将组件拆分为html / js并单独获取每个组件。使用$ q.all等待两次提取。
  • 使用ocLazyLoad使用$ controllerProvider
  • 全局注册控制器
  • 在$ templateCache中获取并存储模板。