2016-03-15 115 views
-1

我有一个非常简单的AngularJS SPA,使用UI路由器在两个视图之间切换。点击主页链接后,用户将看到一行文字。关于链接也应该这样做,但它的路由配置为使用templateUrl而不是一个模板字符串:AngularJS UI路由器:何处包含控制器脚本

$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!"; 
}]); 

注意两个控制台陈述,帮我诊断问题。

问题:当控制器脚本文件执行时,控制器本身永远不会被调用。所以也看不到文本,用户只要看到:

{{消息}}

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

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

真正的问题: 在这个非常简单的和人为的例子,它是合理的,包括在SPA的主要页面的所有控制器的脚本。但即使是一个非常简单的Web应用程序,也可能有几十个页面和数十个控制器。将所有控制器添加到主页面并不能很好地提升性能,并且不能很好地进行维护。

那么设置它的适当方法是什么?控制器脚本应该如何/包括在哪里?

编辑:我忘了提及我收到的错误(是的,我知道)。随着about.html script标签,我收到一条消息说

参数“aboutController”不是一个函数,得到了不确定

这直接发生在控制台消息“注册aboutController”之后。如果我将脚本标记移动到index.html中以包含控制器,则不显示任何错误。同样,对我来说,这表示控制器根本无法及时拨打电话。移动到index.html,它在需要时被完全注册。

+0

如果您在页面上看到字面意思是“{{message}}”,那意味着该模板根本没有被处理。如果Angular没有处理模板,如果没有填充“消息”,则只会看到任何内容。这指出产生致命错误的事物。你有没有检查你的Javascript控制台的错误? – deceze

+0

为什么你的模板包含整个HTML文件?它应该只包含与特定视图相关的片段。你也不能在文件中使用'ng-controller',因为你已经在路由器中使用'controller:...'了。您必须将带有控制器的文件包含在您的主文件中,作为您的主模块的依赖项,否则路由器在尝试加载您的路由时找不到控制器。 – deceze

+0

@deceze我花了一些时间在plunker的readme.md文档中制作了一个更完整的描述,并且忘记了在这里提到错误。是的,有一个关于控制器不是一个函数的错误。这会在我的控制台消息“Registered aboutController。”后直接显示。如果我将脚本标记移至index.html,则消息将消失。所以即使注册控制器的脚本及时执行,实际的控制器也不能被创建。我会把这个添加到问题中。感谢您指出。 –

回答

1

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

  1. requireJS,允许我在运行时轻松加载脚本。由于需要动态加载所有,我需要为我们所有的指令和第三方控件设置依赖关系,因此结束了大量的工作。你可以没有requireJS,但它根本不值得麻烦。
  2. 更改状态调用以使用resolve()提供控制器。这实际上是一种黑客攻击,因为resolve()函数实际上是为了加载控制器的依赖关系,但是在这一点上加载控制器的脚本工作得很好。这样做的更简单的方法涉及使用angularAMD,它提供了一个简单的包装看起来像下面的代码片段。不幸的是,它并没有给你机会从参数动态构建控制器名称,所以我最终自己决定了重写决定。如果您的需求更简单,那么使用angularAMD是明显的选择。

这里是什么样子时,通常指定的观点类似:

$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上传的一个庞大的样本项目中挑选出来。我不追踪为什么这是必要的,但博客文章仍然值得阅读。

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到整个家庭。HTML,但是如果你需要有绑定到页面的一小部分的控制器,你可以像这样将它绑定:

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

控制器将是仅此专区内提供。

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

+0

问题是关于ui路由器,正是因为这是我选择用于ngRoute的地方。谷歌可以给你所有的理由,但在我看来,主要是因为需要多个命名的视图。 –

0

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

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