【问题标题】:How to have controllers in separate file in AngularJS如何在AngularJS中的单独文件中拥有控制器
【发布时间】:2016-01-11 18:59:50
【问题描述】:

我环顾四周,没有找到适合我当前情况的答案。我有一个 app.js 文件:

'use strict';

var demoApp = angular.module('demoApp', [
    // Dépendances du "module" <-- demoApp
    'ngRoute',
    'routeAppControllers',
    'todoList'
]);

demoApp.config(['$routeProvider', '$locationProvider',
    function($routeProvider, $locationProvider) { 

        // Système de routage
        $routeProvider
        .when('/home', {
            templateUrl: 'views/home.html',
            controller: 'homeCtrl'
        })
        .when('/contact/:msg?', {
            templateUrl: 'views/contact.html',
            controller: 'contactCtrl'
        })
        .when('/todolist', {
            templateUrl: 'views/todolist.html',
            controller: 'listeCtrl'
        })
        .when('/testfiltre', {
            templateUrl: 'views/testfiltre.html',
            controller: 'demoFiltreCtrl'
        })
        .when('/testCreationfiltre', {
            templateUrl: 'views/testcreationfiltre.html',
            controller: 'demoCreationFiltreCtrl'
        })
        .otherwise({
            redirectTo: '/home'
        });
    }
]);



var routeAppControllers = angular.module('routeAppControllers', []);

routeAppControllers.controller('homeCtrl', ['$scope',
    function($scope){
        $scope.message = "Bienvenue sur la page d'accueil";
    }
]);

routeAppControllers.controller('contactCtrl', ['$scope','$routeParams',
    function($scope, $routeParams){
        $scope.message = "Laissez-nous un message sur la page de contact !";
        $scope.msg = $routeParams.msg || "Bonne chance pour cette nouvelle appli !";
    }
]);

routeAppControllers.controller('listeCtrl', [function(){}]);

我在 todolist_controller.js 中有 todolist 模块:

var todoList=angular.module('todoList',[]);

todoList.controller('todoCtrl', ['$scope',
    function ($scope) {

        var todos = $scope.todos = [];

        $scope.addTodo = function () {
            var newTodo = $scope.newTodo.trim();
            if (!newTodo.length) {
                return;
            }
            todos.push({
                title: newTodo,
                completed: false
            });

            $scope.newTodo = '';
        };

        $scope.removeTodo = function (todo) {
            todos.splice(todos.indexOf(todo), 1);
        };

        $scope.markAll = function (completed) {
            todos.forEach(function (todo) {
                todo.completed = completed;
            });
        };

        $scope.clearCompletedTodos = function () {
            $scope.todos = todos = todos.filter(function (todo) {
                return !todo.completed;
            });
        };
    }
]);

我有我的 index.html 页面:

<!DOCTYPE html>
    <html lang="fr" ng-app="demoApp">
        <head>
            <meta charset="utf-8" />
            <title>Demo App</title>        
            <link rel="stylesheet" href="styles/style.css">
            <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.2/angular.js"></script>
            <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.2/angular-route.js"></script>
            <script src="https://cdnjs.cloudflare.com/ajax/libs/angular-i18n/1.4.2/angular-locale_fr-ca.min.js"></script>
            <script src="scripts/controllers/app.js"></script>
            <script src="scripts/controllers/todolist_controllers.js"></script>
        </head>
        <body>
            <div ng-view>
            </div>
            <nav>
                <a href="#/home" class="btn btn-primary">Page d'accueil</a>
                <a href="#/contact" class="btn btn-success">Page de contact</a>
                <a href="#/todolist" class="btn btn-primary">Todo list</a>
                <a href="#/testfiltre" class="btn btn-success">test filtre</a>
                <a href="#/testCreationfiltre" class="btn btn-primary">test création filtre</a>
            </nav>
        </body>
    </html>

我读到我想调用,例如,我的主模块 App 和我的所有其他模块文件应该以:angular.module('App').controller(...

但是,这意味着如果我将应用程序的名称从“app”更改为“my_app”,我将不得不通过所有控制器并将“app”更改为“my-app”。

我想避免这种情况,只需要在 index.html 中导入我的文件,只需在我的“应用”模块的依赖项中声明它。

【问题讨论】:

  • 你可能想看看 RequireJS。可以通过RequireJS加载其他依赖(js文件)
  • @Amir,虽然是正确的,但这不是 Angular 中的首选方式。使用 RequireJS 很痛苦。

标签: javascript angularjs


【解决方案1】:

角结构

当你构建一个 Angular 应用程序时,你应该尽可能地分开以使你的代码具有可读性。您应该为 Web 应用程序的每个页面/部分创建一个模块。

示例

Here 是这种结构的一个例子,我写了这个并将它用作 Angular 应用程序的基础。

应用文件夹

这个文件夹包含你所有的组件和路由。

routes.js

这个文件有你项目的状态并且是它自己的模块

app.js

此文件只是您可以将所有其他模块称为依赖项的基础。

var app = angular.module("myApp",   [
                                    'ui.bootstrap',
                                    'ngAnimate',
                                    'myAppRouter',
                                    'myAppHomeCtrl',
                                    'myAppHomeService',
                                    'myAppNavbarDirective',
                                    'myAppNavbarService',
                                    'myAppLoginCtrl',
                                    'myAppLoginService'
                                ]);

您可以在此处查看编写和添加的所有不同模块。看到这被称为 myApp 的方式了吗?好吧,我们在 html 中调用该部分

<html ng-app="myApp">

组件

这将包含诸如“home”和“contact”之类的东西,这些文件夹应该包含所有需要的东西,包含在小的自包含 html、控制器和服务中。

控制器/模块

这是真正回答您问题的部分,为您执行以下操作的控制器添加新模块。

angular.module('myAppHomeCtrl', []).controller('homeCtrl', ['$scope', 'homeContent', function($scope, homeContent){

    $scope.dataset = homeContent.getContent();
    $scope.header = homeContent.getHeader();
    $scope.subheading = homeContent.getSubheader();

}]);

服务/工厂

所以你可以看到,在我们称为工厂的模块中,它也在这个文件夹中,看起来像这样。

angular.module('myAppHomeService', [])

.factory('homeContent', function(){
  return {
    getHeader: function(){
        return "Welcome Human";
    },
    getSubheader: function(){
        return "To Joe's Awesome Website";
    },
  };
});

返回 index.html

所以回到我们的索引中,我们可以像这样在&lt;script&gt;标签中添加所有这些模块。

<!-- Angular Modules -->
<script type="text/javascript" src="app/app.module.js"></script>
<script type="text/javascript" src="app/app.routes.js"></script>
<script type="text/javascript" src="app/components/home/homeCtrl.js"></script>
<script type="text/javascript" src="app/components/home/homeService.js"></script>
<script type="text/javascript" src="app/shared/navigation-bar/navbarDirective.js"></script>
<script type="text/javascript" src="app/shared/navigation-bar/navbarService.js"></script>
<script type="text/javascript" src="app/components/login/loginCtrl.js"></script>
<script type="text/javascript" src="app/components/login/loginService.js"></script>

在生产中,您将缩小所有这些,但在开发中您可以像这样调用它们。

结论

最后,我将做一个总结,以确保您拥有使模块正常工作所需的一切

  1. 转到您的 app.js(主要角度模块)并将名称应用到它。
  2. 转到您的组件并创建新模块
  3. 转到 index.html 并添加链接到新模块的脚本标记
  4. 现在您可以随意使用控制器和所有组件

我希望这个角度结构指南对您有所帮助。祝你好运

【讨论】:

  • 什么是'homeContent'
  • @KévinDuguay homeContent 是我工厂的名称,它在控制器中调用以允许我访问 homeContent 功能。在这种情况下,它只会得到 2 个不同的字符串。
  • 我需要这个吗?它只是为您的应用程序而存在吗?没有它我可以让它工作吗?
  • 不,你不需要它,但你应该把诸如 $http 调用之类的东西放在一个服务/工厂中,以保持你的代码可读。
  • 谢谢你,它完全有效,我真的很喜欢你组织目录的方式。但我还有一个问题:为什么有一个文件夹“shared/navigation-bar”,为什么它是“shared/”
【解决方案2】:

不要将应用程序定义为var app = angular.module('myApp', []);,而是使用angular.module('myApp', []); var 没有必要。然后在 somethingCtrl.js 之类的单独文件中,您可以定义如下控制器:

angular.module('myApp')
    .controller('somethingCtrl', ['$scope', function ($scope) {
    }]);`  

那么你可以在html上按顺序添加脚本标签。首先从模块定义开始。使用 these 角度样式指南

选项 2

定义你的第一个模块。然后您定义各种其他模块并将它们用作依赖项,就像这样

index.js:

angular.module('mainApp', ['otherApp']);

其他.js

angular.module('otherApp', []);

这使您可以灵活地将所有控制器添加到一个模块,并将所有指令添加到另一个模块。您可以通过使用模块作为依赖项来混合功能。只需确保 mainApp 在脚本标记顺序中首先加载即可。

【讨论】:

  • 我知道,但我要问的是我的每个单独的文件都有自己的模块,我可以只导入这些文件并告诉 app.js 中的主模块他需要我的其他模块。我不想为我的外部文件的模块使用相同的名称。例如,我的应用使用 app 模块,但我的 todolist 使用 todo 模块。
  • 我已经更新了答案。告诉我选项 2 是否是您正在寻找的功能。
【解决方案3】:

这就是requirejsbrowserify 可以为您提供极大帮助的地方。但是,由于您的问题与其中任何一个都无关,您可以使用好的 ol' JS 来完成类似的事情。

以您的app.js 文件为例。构建一个全局配置对象,然后在任何地方引用应用程序名称时使用它。然后只是将配置对象中的应用程序名称更改为其他名称而不破坏任何其他组件。

var config = {
    app : "myApp"
}

angular.module(config.app, ["ngAnimate"]);

现在controller.js 中的控制器可以使用相同的配置对象。

angular.module(config.app)
       .controller("myController", function($scope) { ... }

只要您首先加载app.js,您就可以使用配置对象。

<script src="/js/app.js"></script>
<script src="/js/controller.js"></script>

这不漂亮,如果你想要这种没有需要可怕的全局对象/变量。

【讨论】:

  • 但是,对于小型项目,script 标签不是首选吗?我的意思是,这是一种选择,但一般来说?
  • @weirdpanda 当然,没有必要对小型项目的前端构建过于疯狂(除非您对它非常满意并且准备好快速简单的设置)
【解决方案4】:

说这是你的目录布局:

├── controllers
│   └── home.js
├── directives
└── index.html

您像往常一样在home.js 中定义您的控制器,然后将其包含在index.html 中:

...
<script src="./controllers/home.js"></script>
...

【讨论】:

  • 听不懂你的回答
猜你喜欢
  • 2014-07-30
  • 1970-01-01
  • 2015-06-23
  • 1970-01-01
  • 1970-01-01
  • 2015-12-27
  • 1970-01-01
  • 2016-03-27
  • 1970-01-01
相关资源
最近更新 更多