如何组织和减少AngularJS控制器的大小?

时间:2015-09-01 18:50:12

标签: javascript angularjs angularjs-directive angularjs-controller

我正在构建我的第一个AngularJS应用程序,并且正在努力弄清楚如何将我的代码组织到服务/工厂和指令中。我的控制器代码越来越长,我知道我一定做错了。

最初我的应用程序有三个控制器:" BuildingTypeController"," AddressController"和" LayoutController"。我使用ng-controller指令将每个控制器附加到我的每个字段集。但是我遇到了以下问题:

  1. 我需要将一个控制器的数据传递给另一个控制器才能在$ scope。$ watch code中使用。
  2. 当我需要将一个控制器的数据传递给我的Get ... $ http.get方法中的另一个控制器时(在下面的代码中替换为硬编码值)。
  3. 然后我回去把所有的属性和功能都带到了一个大的#34; FormController"中。这为我提供了我正在寻找的功能,但是我知道这可能是组织所有代码的正确方法。

    如果有人能就如何将长控制器构造成更小的部分提出任何建议,我将非常感激。谢谢!

    编辑:创建此代码中的硬编码数据集是为了让小提琴工作 - 它们将被数据库调用替换,不应该被考虑到"长度"单控制器。

    
    
    var app = angular.module('formBuilder', []);
    
    app.controller('FormController', ['$http', '$scope', function ($http, $scope) {
        
        //This could really be thought of as "BuildingTypeController"
        var form = this;
    
        form.state = "";
        form.states = [];
    
        form.buildingType = "";
        form.buildingTypes = [];
    
        form.GetStates = function (buildingType) {
            //This will be replaced with $http.get later
            if (buildingType == null)
            {
             	form.states = ["AZ","CT","NY"];   
            }
            if (buildingType == "Single Story") {
                form.states = ["AZ","CT"];
            }
            if (buildingType == "Mansion") {
                form.states = ["CT"];
            }
            if (buildingType == "Apartment") {
                form.states = ["CT","NY"];
            }
            if (buildingType == "Sky Scraper") {
                form.states = ["NY"];
            }
            
        };
    
        form.GetBuildingTypes = function (state) {
            //This will be replaced with $http.get later
            if (state == null)
            {
             	form.buildingTypes = ["Single Story","Mansion","Apartment","Sky Scraper"];   
            }
            if (state == "AZ") {
                form.buildingTypes = ["Single Story"];
            }
            if (state == "CT") {
                form.buildingTypes = ["Single Story", "Mansion","Apartment"];
            }
            if (state == "NY") {
                form.buildingTypes = ["Sky Scraper", "Apartment"];
            }
        };
    
        //initializations
        form.GetStates();
        form.GetBuildingTypes();
    
        //This could really be thought of as "AddressController"
        form.addressId = "";
        form.addresses = [];
    
        form.GetAddresses = function (form) {
            //This will be replaced with $http.get later
            if (form.state == "AZ" && form.buildingType == "Single Story") {
                form.addresses = [{
                    addressId: 1,
                    description: "123 Grove Ave"
                },{
                    addressId: 2,
                    description: "2352 High Court"
                }];
            }
            if (form.state == "CT" && form.buildingType == "Single Story") {
                form.addresses = [{
                    addressId: 3,
                    description: "1515 Lark Ave"
                },{
                    addressId: 4,
                    description: "2 Front St"
                }];
            }
            if (form.state == "CT" && form.buildingType == "Mansion") {
                form.addresses = [{
                    addressId: 5,
                    description: "6 Waterfront Dr"
                }]
            }
            if (form.state == "CT" && form.buildingType == "Apartment") {
                form.addresses = [{
                    addressId: 6,
                    description: "13 Center St"
                },{
                    addressId: 7,
                    description: "5985 Elizabeth Court "
                }]
            }
            if (form.state == "NY" && form.buildingType == "Sky Scraper") {
                form.addresses = [{
                    addressId: 8,
                    description: "13245 12th Ave"
                },{
                    addressId: 9,
                    description: "345 Park Ave"
                }]
            }
            
            if (form.state == "NY" && form.buildingType == "Apartment") {
                form.addresses = [{
                    addressId: 10,
                    description: "6668 115th St"
                },{
                    addressId: 11,
                    description: "2839 3rd Ave"
                }]
            }
    
        };
    
        form.performAction = function (expr) {
            return function () {
                if (expr == "GetAddresses") {
                    form.GetAddresses($scope.form);
                }
                if (expr == "GetLayouts") {
                    form.GetLayouts($scope.form);
                }
            };
        };
    
        $scope.$watch('form.state', form.performAction('GetAddresses'));
        $scope.$watch('form.buildingType', form.performAction('GetAddresses'));
    
        
        //This could really be thought of as "LayoutController"
        form.layout = {};
        form.layouts = [];
    
        form.GetLayouts = function (form) {
            if (form.addressId == 1)
            	form.layouts = ["A", "B", "C", "D"];
            if (form.addressId == 2)
            	form.layouts = ["B", "C", "D"];
            if (form.addressId == 3)
            	form.layouts = ["A", "D"];
            if (form.addressId == 4)
            	form.layouts = ["A", "D"];
            if (form.addressId == 5)
            	form.layouts = ["A"];
            if (form.addressId == 6)
            	form.layouts = ["D"];
            if (form.addressId == 7)
            	form.layouts = ["C", "D"];
            if (form.addressId == 8)
            	form.layouts = ["A", "D"];
            if (form.addressId == 9)
            	form.layouts = ["A", "B"];
            if (form.addressId == 10)
            	form.layouts = ["B", "C", "D"];
            if (form.addressId == 11)
            	form.layouts = ["C", "D"];
        };
    
        $scope.$watch('form.addressId', form.performAction('GetLayouts'));
    
    }]);
    
    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
    <div ng-app="formBuilder">
        <form name="createForm" class="form-horizontal" ng-controller="FormController as form" novalidate>
            <fieldset>
                <legend>Building Type</legend>
                <select class="form-control" ng-model="form.state" ng-options="state for state in form.states" ng-change="form.GetBuildingTypes(form.state)">
                    <option value="">Select a state</option>
                </select>
                <select class="form-control" ng-model="form.buildingType" ng-options="buildingType for buildingType in form.buildingTypes" ng-change="form.GetStates(form.buildingType)">
                    <option value="">Select a building type</option>
                </select>
            </fieldset>
            
            <fieldset>
                <legend>Specific Address</legend>
                <select class="form-control" ng-model="form.addressId" ng-options="obj.addressId as obj.description for obj in form.addresses">
                    <option value="">Select an address</option>
                </select>
            </fieldset>
            
            <fieldset>
                <legend>Select Room</legend>
                <select class="form-control" ng-model="form.layout" ng-options="layout for layout in form.layouts">
                    <option value="">Select a room</option>
                </select>
            </fieldset>
        </form>
    </div>
    &#13;
    &#13;
    &#13;

3 个答案:

答案 0 :(得分:1)

可以减少控制器中行数的一种方法是将一些硬编码数据集抽象为静态JavaScript文件。你认为控制器中任何可能被抽象出来的东西都可能是一个需要改进的地方。

一个例子可以是创建一个全局数据变量,您可以在其中访问该页面上的变量。

(function(global){
  global.data = {
    names: ['Jane', 'John', 'Mary', 'Michael', 'Ryan', 'Rachel']
  };
})(this);

以下是控制器中的使用示例。

(function(global){
  app.controller('MainController', function($log){
    this.message = "Hello, world!";
    //Usage of the global variable here.
    this.names = global.data.names;
    this.click = function(){
      global.handlers.onclick(this);
    };
  });
})(this);

以下是视图中的使用示例。

<!DOCTYPE html>
<html ng-app="TestModule">

  <head>
    <link rel="stylesheet" href="style.css">
    <!-- Reference to Angular on CDN -->
    <script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.4.5/angular.min.js"></script>
    <!-- Reference to external data sets -->
    <script src="data.js"></script>
    <!-- Reference to external event handlers -->
    <script src="handlers.js"></script>
    <!-- Angular module init -->
    <script src="module.js"></script>
    <!-- Controller init -->
    <script src="maincontroller.js"></script>
  </head>

  <body>
    <div ng-controller="MainController as main">
      <h3>{{ main.message }}</h3>
      <div>
        <h2>Names from the global data.js file:</h2>
        <h3 ng-repeat="n in main.names">{{ n }}</h3>
      </div>
      <div>
        <input type="button" ng-click="main.click()" value="Click me!" />
      </div>
    </div>
  </body>

</html>

请参阅我的plunker了解一个工作示例:

http://plnkr.co/edit/seCQiNpYwKbgjkngdCFz?p=preview

答案 1 :(得分:0)

这里有三个基本要做的事情:

  1. 在新文件中抽象数据

  2. 使用服务使您的控制器不知道数据的来源 检索

  3. (不太基本)使用UI路由器将您的应用分成状态

  4. 这是excellent resource for going into more details

答案 2 :(得分:0)

您可以使用任何装饰器,库或其他语言。在示例中,我编写了自己的库来优化AngularJS和TypeScript的工作。

https://github.com/aleksey-pastuhov/AngularJS-Typed-Core

P.S。:示例现在不起作用,但我很快就会修复它。