在AngularJS中是否存在一致的声明$ scope变量的模式?

时间:2014-11-07 12:02:54

标签: javascript angularjs

AngularJS看起来很乱,难以阅读。在控制器中的$ scope访问的一些非常抽象的netherworld中存在一个模型。一旦我有一个100行长的控制器,一个50行长的部分模板,15个指令和凌乱的CSS类行为,它很难保持变量,他们做什么,以及它们在代码中的位置。

我正在查看Todo应用示例:

angular.module('todomvcApp')
  .controller('MainCtrl', function ($scope, $timeout, Todo, filterFilter, $location) {
    $scope.todos = [];
    $scope.newTodo = '';
    $scope.editedTodo = null;
    $scope.status = $location.search().q || '';

//.............

    $scope.$watch('todos', function () {
      $scope.remainingCount = filterFilter($scope.todos, { completed: false }).length;
      $scope.completedCount = $scope.todos.length - $scope.remainingCount;
      $scope.allChecked = !$scope.remainingCount;
    }, true);

//............

    $scope.editTodo = function (id) {
      $scope.editedTodo = $scope.todos[id];
      $scope.originalTodo = angular.extend({}, $scope.editedTodo);
    };

//............

    $scope.revertEditing = function (id) {
      $scope.todos[id] = $scope.originalTodo;
      $scope.doneEditing(id);
    };


  });

以下是一些需要初始化的$ scope变量:

$scope.todos
$scope.newTodo
$scope.editedTodo
$scope.status

但是,为什么其他不需要初始化的$ scope变量也未在作者的早期定义?例如

$scope.orginialTodo

这使得代码在部分模板和控制器中都很难读取。是否有一种结构或模式可以帮助清除Angular中的变量组织?

2 个答案:

答案 0 :(得分:1)

我个人发现使用_.extend(或angular.extend)来初始化/定义范围属性看起来比每行一次的$ scope.XX = X更清洁,并且有助于文件的可读性。

我也总是在控制器/链接fn的开头初始化变量,即使变量将被异步设置。这允许在使用一个文件时非常快速地查看所有变量,而不会错过稍后初始化的文件。

你拥有的变量越多,就越真实。

_.extend($scope, {
    todos       : [],
    newTodo     : '',
    editedTodo  : null // even if if will be initialized later
}); 

你的例子或多或少会有以下几点:

angular.module('todomvcApp')
    .controller('MainCtrl', function ($scope, $timeout, Todo, filterFilter, $location) {

        _.extends($scope, {
            todos : [],
            newTodo : '',
            editedTodo : null,
            status : $location.search().q || ''
        });

        // .............

        $scope.$watch('todos', function (todos) {
            _.extend($scope, {
                remainingCount : filterFilter(todos, { completed: false }).length,
                completedCount : todos.length - $scope.remainingCount,
                allChecked     : $scope.remainingCount 
            });
        }, true);

        // ............

        $scope.editTodo = function (id) {
            $scope.editedTodo = $scope.todos[id];
            $scope.originalTodo = angular.extend({}, $scope.editedTodo);
        };

        // ............

        $scope.revertEditing = function (id) {
            $scope.todos[id] = $scope.originalTodo;
            $scope.doneEditing(id);
        };


    });

答案 1 :(得分:0)

是的。基本上,避免范围汤。 在构造函数中声明您的属性,并使用' this'来访问它们。 你应该避免建立你的范围对象......

  

为什么呢?将方法和属性直接放在控制器上,而不是构建范围对象,更适合Google Closure类样式。另外,使用'控制器作为'当多个控制器应用于元素时,显而易见的是您正在访问哪个控制器。因为总有一个'。在绑定中,您不必担心原型继承掩盖原语。

在版本1.2之后,控制器'作为'语法使这更加简化。

这个方法可能会自然产生一个问题,"如何在构造函数之外访问我注入的服务"?...

How should I reference services in my controller functions without using scope?

Angular Style Guide

Syle指南示例

不使用Controller别名

<div ng-controller="hello.mainpage.HomeCtrl"/>
  <span ng-class="homeCtrl.myColor">I'm in a color!</span>
  <span>{{homeCtrl.add(5, 6)}}</span>
</div>


 /**
 * Home controller.
 */
hello.mainpage.HomeCtrl = function($scope) {
  $scope.homeCtrl = this; // This is a bridge until Angular 1.2 controller-as
  this.myColor = 'blue';
};


hello.mainpage.HomeCtrl.prototype.add = function(a, b) {
  return a + b;
};

版本1.2之后,使用Controller-as Syntax

<div ng-controller="hello.mainpage.HomeCtrl as homeCtrl"/>
  <span ng-class="homeCtrl.myColor">I'm in a color!</span>
  <span>{{homeCtrl.add(5, 6)}}</span>
</div>

/**
 * Home controller.
 */
hello.mainpage.HomeCtrl = function() {
  this.myColor = 'blue';
};

hello.mainpage.HomeCtrl.prototype.add = function(a, b) {
  return a + b;
};

最后,尝试使用这些指南重构原始Todo(1.2后指南)

var MainCtrl = function($timeout, Todo, filterFilter, $location){

  var that =this;

  this.todos = [];
  this.newTodo = '';
  this.editedTodo = null;
  this.originalTodo = null;
  this.status = $location.search().q || '';


  this.$watch('todos',function(){
    that.remainingCount = filterFilter(that.todos, { completed: false }).length;
    that.completedCount = that.todos.length - that.remainingCount;
    that.allChecked = !that.remainingCount;
  });
};

MainCtrl.prototype.editTodo = function (id) {
  this.editedTodo = this.todos[id];
  this.originalTodo = angular.extend({}, this.editedTodo);
};

MainCtrl.prototype.revertEditing = function(){
  this.todos[id] = this.originalTodo;
  this.doneEditing(id);
};

MainCtrl.$inject=['$timeout', 'Todo', 'filterFilter', '$location'];