AngularJs Understanding the Controller Component

在angular中,controller是一个javascript 函数(type/class),被用作扩展除了root scope在外的angular scope(http://www.jb51.net/article/91749.htm)的实例。当我们或者angular通过scope.$new API(http://docs.angularjs.org/api/ng.$rootScope.Scope#$new)创建新的child scope时,有一个选项作为方法的参数传入controller(这里没看明白,只知道controller的第一个参数是一个新创建的scope,有绑定parent scope)。这将告诉angular需要联合controller和新的scope,并且扩展它的行为。

  controller可以用作:

1.设置scope对象的初始状态。
2.增加行为到scope中。

一、 Setting up the initial state of a scope object(设置scope对象的初始状态)

  通常,当我们创建应用的时候,我们需要为angular scope设置初始化状态。

  angular将一个新的scope对象应用到controller构造函数(估计是作为参数传进去的意思),建立了初始的scope状态。这意味着angular从不创建controller类型实例(即不对controller的构造函数使用new操作符)。构造函数一直都应用于存在的scope对象。

  我们通过创建model属性,建立了scope的初始状态。例如:

function GreetingCtrl ($scope) {$scope.greeting = “Hola!”;}

  “GreetingCtrl”这个controller创建了一个叫“greeting”的,可以被应用到模版中的model。

二、 Adding Behavior to a Scope Object(在scope object中增加行为)

  在angular scope对象上的行为,是以scope方法属性的形式,供模版、视图使用。这行为(behavior)可以修改应用的model。

  正如指引的model章节(http://www.jb51.net/article/91777.htm)讨论的那样,任意对象(或者原始的类型)赋值到scope中,成为了model属性。任何附加到scope中的function,对于模版视图来说都是可用的,可以通过angular expression调用,也可以通过ng event handler directive调用(如ngClick)。

三、 Using Controllers Correctly

  一般而言,controller不应该尝试做太多的事情。它应该仅仅包含单个视图所需要的业务逻辑(还有点没转过弯了,一直认为Controller就是个做转发的……)。

  保持Controller的简单性,常见办法是抽出那些不属于controller的工作到service中,在controller通过依赖注入来使用这些service。这些东西会在向导的Dependency Injection Services章节中讨论。

  不要在Controller中做以下的事情:

  1. 任何类型的DOM操作 - controller应该仅仅包含业务逻辑。DOM操作,即应用的表现逻辑,它的测试难度是众所周知的。将任何表现逻辑放到controller中,大大地影响了应用逻辑的可测试性。angular为了自动操作(更新)DOM,提供的数据绑定(http://docs.angularjs.org/guide/dev_guide.templates.databinding)。如果我们希望执行我们自定义的DOM操作,可以把表现逻辑抽取到directive(http://www.jb51.net/article/91739.htm)中。
  2. Input formatting(输入格式化) - 使用angular form controls (http://www.jb51.net/article/91744.htm)代替。
  3. Output filtering (输出格式化过滤) - 使用angular filters 代替。
  4. 执行无状态或有状态的、controller共享的代码 - 使用angular services 代替。
  5. 实例化或者管理其他组件的生命周期(例如创建一个服务实例)。

四、 Associating Controllers with Angular Scope Objects

  我们可以显式地通过scope.$new关联controller和scope对象,或者隐式地通过ngController directive(http://docs.angularjs.org/api/ng.directive:ngController)或者$route service(http://docs.angularjs.org/api/ng.$route)。

  1. Controller 构造函数和方法的 Example

  为了说明controller组件是如何在angular中工作的,让我们使用以下组件创建一个小应用:

  1. 一个有两个按钮和一个简单消息的template。
  2. 一个由名为”spice”的字符串属性组成的model。
  3. 一个有两个设置spice属性的方法的controller。

  在我们的模版里面的消息,包含一个到spice model的绑定,默认设置为”very”。根据被单击按钮,将spice model的值设置为”chili”或者” jalapeño”,消息会被数据绑定自动更新。

<!DOCTYPE html>
<html ng-app>
<head>
 <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
 <title>spicy-controller</title>
 <meta content="IE=edge,chrome=1" http-equiv="X-UA-Compatible">
 <style type="text/css">
 .ng-cloak {
  display: none;
 }
 </style>
</head>
<body class="ng-cloak">
 <div ng-controller="SpicyCtrl">
 <button ng-click="chiliSpicy()">Chili</button>
 <button ng-click="jalapenoSpicy('jalapeño')">Jalapeño</button>
 <p>The food is {{spice}} spicy!</p>
 </div>

 <script src="../angular-1.0.1.js" type="text/javascript"></script>
 <script type="text/javascript">
 function SpicyCtrl($scope) {
  $scope.spice = "very";
  $scope.chiliSpicy = function() {
  $scope.spice = "chili";
  };
  $scope.jalapenoSpicy = function(val) {
  this.spice = val;
  };
 }
 </script>
</body>
</html>

  在上面例子中需要注意的东东:

  1. ngController directive被用作为我们的模版(隐式)创建scope,那个scope会称为SpicyCtrl的参数。
  2. SpicyCtrl只是一个普通的javascript function。作为一个(随意)的命名规则,名称以大写字母开头,并以”Ctrl”或者”Controller”结尾。
  3. 对属性赋值可以创建或者更新$scope的model。
  4. controller方法可以通过直接分配到$scope实现创建。(chiliSpicy方法)
  5. controller的两个方法在template中都是可用的(在ng-controller属性所在的元素以及其子元素中都有效)。
  6. 注意:之前版本的angular(1.0RC之前)允许我们使用this来代替$scope定义$scope的方法,但这里不再适用。在定义在scope上的方法中,this跟$scope是等价的(angular将this至为scope),但不是在我们的controller构造函数中。
  7. 注意:之前版本的angular(1.0RC之前),会自动增加controller的prototype方法到scope中,但现在不会了。所有方法都需要人工加入到scope中。(印象中之前有一个guide,有用过这个。还没更新-_-!)

  controller方法可以带参数的,正如下面例子所示:

<!DOCTYPE html>
<html ng-app>
<head>
 <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
 <title>controller-method-aruments</title>
 <meta content="IE=edge,chrome=1" http-equiv="X-UA-Compatible">
 <style type="text/css">
 .ng-cloak {
  display: none;
 }
 </style>
</head>
<body class="ng-cloak">
 <div ng-controller="SpicyCtrl">
 <input ng-model="customSpice" value="wasabi"/>
 <button ng-click="spicy(customSpice)">customSpice</button>
 <br/>
 <button ng-click="spicy('Chili')">Chili</button>
 <p>The food is {{spice}} spicy!</p>
 </div>

 <script src="../angular-1.0.1.js" type="text/javascript"></script>
 <script type="text/javascript">
 function SpicyCtrl($scope) {
  $scope.spice = "very";
  $scope.spicy = function(spice) {
  $scope.spice = spice;
  };
 }
 </script>
</body>
</html>

  注意那个SpicyCtrl controller现在只定义了一个有一个参数”spice”、叫”spicy”的方法。template可以引用controller方法并为它传递常量字符串或model值。

  Controller继承在angular是基于scope继承的。让我们看看下面的例子:

<!DOCTYPE html>
<html ng-app>
<head>
 <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
 <title>controller-inheritance</title>
 <meta content="IE=edge,chrome=1" http-equiv="X-UA-Compatible">
 <style type="text/css">
 .ng-cloak {
  display: none;
 }
 </style>
</head>
<body class="ng-cloak">
 <div ng-controller="MainCtrl">
 <p>Good {{timeOfDay}}, {{name}}!</p>
 <div ng-controller="ChildCtrl">
  <p>Good {{timeOfDay}}, {{name}}!</p>
  <p ng-controller="BabyCtrl">Good {{timeOfDay}}, {{name}}!</p>
 </div>
 </div>

 <script src="../angular-1.0.1.js" type="text/javascript"></script>
 <script type="text/javascript">
 function MainCtrl($scope) {
  $scope.timeOfDay = 'Main时间';
  $scope.name = 'Main名称';
 }

 function ChildCtrl($scope) {
  $scope.name = 'Child名称';
 }

 function BabyCtrl($scope) {
  $scope.timeOfDay = 'Baby时间';
  $scope.name = 'Baby名称';
 }
 </script>
</body>
</html>

  注意我们如何嵌套3个ngController directive到模版中的。为了我们的视图,这模版结构将会导致4个scope被创建:

  1. root scope。
  2. MainCtrl scope,包含timeOfDay和name model。
  3. ChildCtrl scope,覆盖了MainCtrl scope的name model,继承了timeOfDay model。
  4. BabyCtrl scope,覆盖了MainCtrl scope 的timeOfDay以及ChildCtrl scope的name。

  继承的工作,在controller和model中是一样的。所以我们前一个例子中,所有model可以通过controller被重写。

  注意:在两个Controller之间标准原型继承不是如我们所想地那样工作的,因为正如我们之前提到的,controller不是通过angular直接初始化的,但相反地,apply了那个scope对象。(controllers are not instantiated directly by angular, but rather are applied to the scope object,这里跟之前一样,我还是没理解。)

五、 Testing Controller

  虽然有很多方法去测试controller,最好的公约之一,如下面所示,需要注入$rootScope和$controller。(测试需要配合jasmine.js)

<!DOCTYPE html>
<html ng-app>
<head>
 <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
 <title>controller-test</title>
 <meta content="IE=edge,chrome=1" http-equiv="X-UA-Compatible">
 <link rel="stylesheet" href="../jasmine.css">
 <style type="text/css">
 .ng-cloak {
  display: none;
 }
 </style>
</head>
<body class="ng-cloak">

<script src="../angular-1.0.1.js" type="text/javascript"></script>
<script src="../angular-scenario-1.0.1.js" type="text/javascript"></script>
<script src="../jasmine.js" type="text/javascript"></script>
<script src="../jasmine-html.js" type="text/javascript"></script>
<script src="../angular-mocks-1.0.1.js" type="text/javascript"></script>
<script type="text/javascript">
 function MyController($scope) {
 $scope.spices = [
  {"name":"pasilla", "spiciness":"mild"},
  {"name":"jalapeno", "spiceiness":"hot hot hot!"},
  {"name":"habanero", "spiceness":"LAVA HOT!!"}
 ];

 $scope.spice = "habanero";
 }
 describe("MyController function", function () {
 describe("MyController", function () {
  var scope;
  beforeEach(inject(function ($rootScope, $controller) {
  scope = $rootScope.$new();
  var ctrl = $controller(MyController, {$scope:scope});
  }));

  it('should create "cpices" model with 3 spices', function () {
  expect(scope.spices.length).toBe(3);
  });

  it('should set the default value of spice', function () {
  expect(scope.spice).toBe("habanero");
  });
 });
 });

 (function () {
 var jasmineEnv = jasmine.getEnv();
 jasmineEnv.updateInterval = 1000;

 var trivialReporter = new jasmine.TrivialReporter();

 jasmineEnv.addReporter(trivialReporter);

 jasmineEnv.specFilter = function (spec) {
  return trivialReporter.specFilter(spec);
 };

 var currentWindowOnload = window.onload;

 window.onload = function () {
  if (currentWindowOnload) {
  currentWindowOnload();
  }
  execJasmine();
 };

 function execJasmine() {
  jasmineEnv.execute();
 }

 })();

</script>
</body>
</html>

  如果我们需要测试嵌套的controller,我们需要在test中创建与DOM里面相同的scope继承关系。

<!DOCTYPE html>
<html ng-app>
<head>
 <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
 <title>controller-test</title>
 <meta content="IE=edge,chrome=1" http-equiv="X-UA-Compatible">
 <link rel="stylesheet" href="../jasmine.css">
 <style type="text/css">
 .ng-cloak {
  display: none;
 }
 </style>
</head>
<body class="ng-cloak">

<script src="../angular-1.0.1.js" type="text/javascript"></script>
<script src="../angular-scenario-1.0.1.js" type="text/javascript"></script>
<script src="../jasmine.js" type="text/javascript"></script>
<script src="../jasmine-html.js" type="text/javascript"></script>
<script src="../angular-mocks-1.0.1.js" type="text/javascript"></script>
<script type="text/javascript">
 function MainCtrl($scope) {
 $scope.timeOfDay = 'Main时间';
 $scope.name = 'Main名称';
 }

 function ChildCtrl($scope) {
 $scope.name = 'Child名称';
 }

 function BabyCtrl($scope) {
 $scope.timeOfDay = 'Baby时间';
 $scope.name = 'Baby名称';
 }

 describe("MyController", function () {
 var mainScope,childScope,babyScope;
 beforeEach(inject(function ($rootScope, $controller) {
  mainScope = $rootScope.$new();
  var mainCtrl = $controller(MainCtrl, {$scope:mainScope});
  childScope = mainScope.$new();
  var childCtrl = $controller(ChildCtrl, {$scope:childScope});
  babyScope = childScope.$new();
  var babyCtrl = $controller(BabyCtrl, {$scope:babyScope});
 }));

 it('should have over and selected', function () {
  expect(mainScope.timeOfDay).toBe("Main时间");
  expect(mainScope.name).toBe("Main名称");
  expect(childScope.timeOfDay).toBe("Main时间");
  expect(childScope.name).toBe("Child名称");
  expect(babyScope.timeOfDay).toBe("Baby时间");
  expect(babyScope.name).toBe("Baby名称");
 });
 });

 (function () {
 var jasmineEnv = jasmine.getEnv();
 jasmineEnv.updateInterval = 1000;

 var trivialReporter = new jasmine.TrivialReporter();

 jasmineEnv.addReporter(trivialReporter);

 jasmineEnv.specFilter = function (spec) {
  return trivialReporter.specFilter(spec);
 };

 var currentWindowOnload = window.onload;

 window.onload = function () {
  if (currentWindowOnload) {
  currentWindowOnload();
  }
  execJasmine();
 };

 function execJasmine() {
  jasmineEnv.execute();
 }

 })();

</script>
</body>
</html>

以上就是关于 AngularJs Understanding the Controller Component的资料整理,后续继续补充相关资料,谢谢大家的支持!

(0)

相关推荐

  • AngularJs学习第五篇从Controller控制器谈谈$scope作用域

    Controller的创建 AngularJs controller使用无处不在,在里代码演示比较简单的创建工作. <!DOCTYPE html> <html xmlns="http://www.w.org//xhtml" ng-app="exampleApp"> <head> <meta http-equiv="Content-Type" content="text/html; charset

  • AngularJs Injecting Services Into Controllers详解

    把service当作被依赖的资源加载到controller中的方法,与加载到其他服务中的方法很相似. 由于javascript是一个动态语言,DI不能弄明白应该通过static types(like in static typed languages)注入哪一个service.因此,我们需要通过$inject属性指定service名称, 它是一个包含需要注入的service名称的字符串数组.service ID顺序的重要性:工厂方法中的参数顺序,与service在数组中的顺序一致.工厂方法的参数

  • AngularJS ng-controller 指令简单实例

    AngularJS ng-controller 指令 AngularJS 实例 为应用变量添加控制器: <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <script src="http://apps.bdimg.com/libs/angular.js/1.4.6/angular.min.js"></script> </head&g

  • AngularJS入门心得之directive和controller通信过程

    AngularJS 通过新的属性和表达式扩展了 HTML.Angularjs学习起来也非常的简单. 1.AngularJS是何方神圣 Angular JS (Angular.JS) 是一组用来开发Web页面的框架.模板以及数据绑定和丰富UI组件.它支持整个开发进程,提供web应用的架构,无需进行手工DOM操作. AngularJS是为了克服HTML在构建应用上的不足而设计的.HTML是一门很好的为静态文本展示设计的声明式语言,但要构建WEB应用的话它就显得乏力了.这里AngularJS就应运而生

  • AngularJS利用Controller完成URL跳转

    具体写法举例: 1.js定义一个controller function MyCtrl($scope, $location) { $scope.jumpToUrl = function(path) { //TODO:add code here }; } 2.html里面应用controller <div ng-controller='MyCtrl'> <button ng-click="jumpToUrl('/signin')">signin</button

  • Angularjs的Controller间通信机制实例分析

    本文实例讲述了Angularjs的Controller间通信机制.分享给大家供大家参考,具体如下: 在Angularjs开发一些经验总结中提到我们需要按照业务区分angular controller,避免过大无所不能的上帝controller,我们把controller分离开了,但是有时候我们需要在controller中通信,一般为比较简单的通信机制,告诉同伴controller我的某个你所关心的东西改变了,怎么办?如果你是一个javascript程序员你会很自然的想到异步回调响应式通信-事件机

  • Angularjs中controller的三种写法分享

    前言 在Angular中,Directive.Service.Filter.Controller都是以工厂方法的方式给出,而工厂方法的参数名对应着该工厂方法依赖的Service.angularjs中controller其实就是一个方法,它有三种写法,下面来一起看看吧. 第一种: <pre name="code" class="javascript">var AppController = ['$scope', function($scope){ $sco

  • AngularJS实践之使用NgModelController进行数据绑定

    前言 在Angular应用中,ng-model指令时不可缺少的一个部分,它用来将视图绑定到数据,是双向绑定魔法中重要的一环.ngModelController则是ng-model指令中所定义的controller.这个controller包含了一些用于数据绑定,验证,CSS更新,以及数值格式化和解析的服务.它不用来进行DOM渲染或者监听DOM事件.与DOM相关的逻辑都应该包含在其他的指令中,然后让这些指令来试用ngModelController中的数据绑定功能. 注意:本篇文章不是对NgMode

  • AngularJS控制器controller正确的通信的方法

    AngularJS是一款非常强大的前端MVC框架,AngularJS中的controller是个函数,用来向视图的作用域($scope)添加额外的功能,我们用它来给作用域对象设置初始状态,并添加自定义行为. 当我们在创建新的控制器时,angularJS会帮我们生成并传递一个新的$scope对象给这个controller,在angularJS应用的中的任何一个部分,都有父级作用域的存在,顶级就是ng-app所在的层级,它的父级作用域就是$rootScope. 每个$scope的$root指向$ro

  • AngularJs根据访问的页面动态加载Controller的解决方案

    用Ng就是想做单页面应用(simple page application),就是希望站内所有的页面都是用Ng的Route,尽量不用location.href,但是这样的webapp好处是很多,但是美中不足的是当你的webapp随着时间的推移,用户变多,功能变得更丰富,controller也变得越来越多,你不得不把所有的controller当作全局模块进行加载,以使得在站内任何一个页面中按F5刷新后能route到任意一个其他页面,而不会发生找不到controller的错误,加载所有的control

  • angularjs学习笔记之三大模块(modal,controller,view)

    今天主要跟大家详细讲解一下angularjs的三大模块: modal,controller,view. 首先跟大家说一下这三个模块之间的关系. 1.数据模型(modal)主要提供数据.它不会和视图(view)直接操作. 2.controller保存modal提供的数据,与视图进行操作. 3.view是视图,也就是页面展示. 4.总而言之,controller负责数据和视图之间的通信,就是两者的接口人.他们分工明确,实现了模块化. 一.如何使用数据模型(modal)? 讲到数据模型,我们再来看一下

随机推荐