使用包含的模板

时间:2016-03-28 14:38:14

标签: javascript angularjs lazy-loading angularjs-ng-include

在代码段中,我尝试使用控件FooCtrl,该控件使用指令app/foo.html在包含的模板common.script中定义。



angular.module('common.script', []).directive('script', function() {
  return {
    restrict: 'E',
    scope: false,
    compile: function(element, attributes) {
      if (attributes.script === 'lazy') {
        var code = element.text()
        new Function(code)()
      }
    }
  }
})
angular.module('app.templates', ['app/foo.html'])
angular.module("app/foo.html", []).run(function($templateCache) {
  $templateCache.put("app/foo.html",
    "<script data-script=\"lazy\">\n" +
    "   console.log('Before FooCtrl')\n" +
    "	angular.module('app').controller('FooCtrl', function($scope) {\n" +
    "		console.log('FooCtrl')\n" +
    "	})\n" +
    "<\/script>\n" +
    "<div data-ng-controller=\"FooCtrl\">app\/foo.html\n" +
    "<\/div>"
  )
})
angular.module('app', ['common.script', 'app.templates']).controller('ApplicationCtrl', function($scope) {
  console.log('ApplicationCtrl')
})
&#13;
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.3/angular.min.js"></script>
<div data-ng-app="app" data-ng-controller="ApplicationCtrl">
  <div data-ng-include="'app/foo.html'"></div>
</div>
&#13;
&#13;
&#13;

但是AngularJS控制台中的预期输出FooCtrl不会抛出:

Error: [ng:areq] Argument 'FooCtrl' is not a function [...]

我不明白为什么!模板中的代码在抛出异常之前执行,因此应该定义控制器。我怎么能解决这个问题?

1 个答案:

答案 0 :(得分:0)

这里真正的问题是资源的延迟加载!关于此主题有大量materialrelated posts

此处的解决方案可能是扩展的common.script指令:

'use strict'

angular.module('common.script', [])

.config(function($animateProvider, $controllerProvider, $compileProvider, $filterProvider, $provide) {
  angular.module('common.script').lazy = {
    $animateProvider: $animateProvider,
    $controllerProvider: $controllerProvider,
    $compileProvider: $compileProvider,
    $filterProvider: $filterProvider,
    $provide: $provide
  }
})

.directive('script', function() {
  return {
    restrict: 'E',
    scope: {
      modules: '=script'
    },
    link: function(scope, element) {
      var offsets = {}, code = element.text()

      function cache(module) {
        offsets[module] = angular.module(module)._invokeQueue.length
      }

      function run(offset, queue) {
        var i, n
        for (i = offset, n = queue.length; i < n; i++) {
          var args = queue[i], provider = angular.module('common.script').lazy[args[0]]

          provider[args[1]].apply(provider, args[2])
        }
      }

      if (angular.isString(scope.modules)) {
        cache(scope.modules)
      } else if (angular.isArray(scope.modules)) {
        scope.modules.forEach(function(module) {
          cache(module)
        })
      }

      /*jshint -W054 */
      new Function(code)()

      Object.keys(offsets).forEach(function(module) {
        if (angular.module(module)._invokeQueue.length > offsets[module]) {
          run(offsets[module], angular.module(module)._invokeQueue)
        }
      })
    }
  }
})

此解决方案的唯一缺点是您必须在script标记中指定要扩展的模块:

<script data-script="'app'">
  angular.module('app').controller('FooCtrl', function($scope) {
    console.log('Works!')
  })
</script>