AngularJS UI路由器:包含控制器脚本的位置

时间:2016-03-15 10:00:46

标签: javascript angularjs controller angular-ui-router

我有一个非常简单的AngularJS SPA,使用UI路由器在两个视图之间切换。单击Home链接后,用户将看到一行文本。 About链接应该相同,但其路由配置为使用templateUrl而不是模板字符串:

  $stateProvider
  .state("home", {
    url: "/home",
    template: "<h3>This is the Home content</h3>"
  })
  .state("about", {
    url: "/about",
    templateUrl: "about.html",
    controller: "aboutController"
  });

about.html就是这么简单:

<!DOCTYPE HTML>
<html ng-app="simpleApp">
<head>
  <title>About</title>
  <script src="aboutcontroller.js"></script>
</head>
<body ng-controller="aboutController">
  <h3>{{message}}</h3>
</body>
</html>

......它的控制器也是一个简单的设计模板:

console.log("Registered aboutController"); ///////////
angular.module("simpleApp")
.controller("aboutController", ["$scope", function ($scope) {
  console.log("Created aboutController"); ///////////
  $scope.message = "This is the About content!";
}]);

请注意帮助我诊断问题的两个控制台语句。

问题:执行控制器脚本文件时,永远不会调用控制器本身。因此,用户不会看到文本,而是看到:

  

{{消息}}

这似乎与我在模板文件(about.html)中包含脚本文件的事实有关。如果我将脚本标记移动到index.html,问题就会消失,一切都按预期工作。

Here's a plunker that shows my problem and workaround.

真正的问题: 在这个非常简单和人为的例子中,将所有控制器脚本包含在SPA的主页中是合理的。但是对于一个非常简单的Web应用程序,可能有几十个页面都有几十个控制器。将所有控制器添加到主页面将无法很好地扩展性能,并且无法很好地进行维护。

那么设置它的适当方法是什么?如何/在何处包含控制器脚本?

编辑:我忘了提到我收到的错误(是的,我知道)。使用about.html中的脚本标记,我收到一条消息说

  

参数'aboutController'不是函数,未定义

这在控制台消息“Registered aboutController”之后直接发生。如果我移动脚本标记以在index.html中包含控制器,则不会显示错误。同样,对我而言,这表明控制器根本无法及时调用。移至index.html,它在需要时完全注册。

3 个答案:

答案 0 :(得分:1)

经过数小时的研究后,我发现了这一点。这些是我需要做的事情:

  1. requireJS,允许我在运行时轻松加载脚本。这最终成为一项庞大的工作量,因为所有需要动态加载,我需要为所有指令和第三方控件设置依赖项。你可以不用requireJS,但它根本不值得麻烦。
  2. 更改状态调用以使用resolve()提供控制器。这实际上是一个hack,因为resolve()函数实际上意味着加载控制器的依赖项,但此时加载控制器的脚本可以正常工作。更简单的方法是使用angularAMD,它提供了一个简单的包装器,看起来像下面的代码片段。不幸的是,它没有给你机会从参数动态构建控制器名称,所以我最终决定自己解决。如果您的需求更简单,那么使用angularAMD是显而易见的选择。
  3. 这里是正常指定视图时的样子:

    $stateProvider.state("home", {
        url: "",
        views: {
        // Other views...
          "client": {
            templateUrl: "clientselection.html",
            controller: "ClientSelectController",
            controllerUrl: "Controllers/ClientSelect.controller"
          }
        }
      });
    

    这与angularAMD的内容相同。不同之处在于控制器现在按需加载:

    $stateProvider.state("home", {
        url: "",
        views: {
        // Other views...
          "client": angularAMD.route({
            templateUrl: "clientselection.html",
            controller: "ClientSelectController",
            controllerUrl: "Controllers/ClientSelect.controller"
          })
        }
      });
    

    值得一提的是Dan Wahlin's terrific blog post。它没有使用UI路由器,但概念是可转移的。不幸的是,帖子只提供了不完整的片段。其余的你需要从他在Github上传的庞大的样本项目中挑选出来。我不理解为什么需要这样做,但博客文章仍然值得一读。

答案 1 :(得分:0)

对于以角度进行路由,你应该使用routeProvider然后你可以像这样用它来导航:

var app = angular.module('moduleName', [
'ngRoute',
'angularModalService'
]);

app.config(['$routeProvider',
function($routeProvider) {
    $routeProvider.
        when('/home', {
        templateUrl: 'partials/home.html',
        controller: 'homeController'
    }).otherwise({
        redirectTo: '/home'
    });

在这里你将homeController绑定到整个home.html,但是如果你需要将一个控制器绑定到页面的一小部分,你可以像这样绑定它:

<div class="row" ng-controller="homeController">
   //Further HTML
</div>

控制器仅在此div中可用。

对于包含部分,我通常会在</body>标记上方定义所有脚本。我将它们分开,首先是像jQuery和AngularJS这样的库,首先是app.js(带有routeProvoder的文件),控制器,然后是服务/工厂和最后的指令

答案 2 :(得分:0)

为了回答你的问题,Angular的设计方式是它加载所有的js文件并将控件赋予角度。加载Js文件时,所有控制器,服务等都在ngApp中注册。这就是为什么建议在index.html本身提供所有脚本文件的原因。

如果您认为在单个index.html中提供所有文件是笨拙的,那么您可以将应用程序拆分为模块然后加载它们。这是让您的应用看起来不那么笨拙的更好方法。