原版地址:http://docs.angularjs.org/guide/dev_guide.mvc.understanding_modeljavascript
在angular中,controller是一个javascript 函数(type/class),被用做扩展除了root scope在外的angular scope(http://www.cnblogs.com/lcllao/archive/2012/09/23/2698651.html)的实例。当咱们或者angular经过scope.$new API(http://docs.angularjs.org/api/ng.$rootScope.Scope#$new)建立新的child scope时,有一个选项做为方法的参数传入controller(这里没看明白,只知道controller的第一个参数是一个新建立的scope,有绑定parent scope)。这将告诉angular须要联合controller和新的scope,而且扩展它的行为。css
controller能够用做:html
1、 Setting up the initial state of a scope object(设置scope对象的初始状态) java
一般,当咱们建立应用的时候,咱们须要为angular scope设置初始化状态。angularjs
angular将一个新的scope对象应用到controller构造函数(估计是做为参数传进去的意思),创建了初始的scope状态。这意味着angular从不建立controller类型实例(即不对controller的构造函数使用new操做符)。构造函数一直都应用于存在的scope对象。chrome
咱们经过建立model属性,创建了scope的初始状态。例如:express
function GreetingCtrl ($scope) {$scope.greeting = “Hola!”;}
“GreetingCtrl”这个controller建立了一个叫“greeting”的,能够被应用到模版中的model。bootstrap
2、 Adding Behavior to a Scope Object(在scope object中增长行为)api
在angular scope对象上的行为,是以scope方法属性的形式,供模版、视图使用。这行为(behavior)能够修改应用的model。mvc
正如指引的model章节(http://www.cnblogs.com/lcllao/archive/2012/09/24/2699861.html)讨论的那样,任意对象(或者原始的类型)赋值到scope中,成为了model属性。任何附加到scope中的function,对于模版视图来讲都是可用的,能够经过angular expression调用,也能够经过ng event handler directive调用(如ngClick)。
3、 Using Controllers Correctly
通常而言,controller不该该尝试作太多的事情。它应该仅仅包含单个视图所须要的业务逻辑(还有点没转过弯了,一直认为Controller就是个作转发的……)。
保持Controller的简单性,常见办法是抽出那些不属于controller的工做到service中,在controller经过依赖注入来使用这些service。这些东西会在向导的Dependency Injection Services章节中讨论。
不要在Controller中作如下的事情:
4、 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中工做的,让咱们使用如下组件建立一个小应用:
在咱们的模版里面的消息,包含一个到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>
在上面例子中须要注意的东东:
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被建立:
继承的工做,在controller和model中是同样的。因此咱们前一个例子中,全部model能够经过controller被重写。
注意:在两个Controller之间标准原型继承不是如咱们所想地那样工做的,由于正如咱们以前提到的,controller不是经过angular直接初始化的,但相反地,apply了那个scope对象。(controllers are not instantiated directly by angular, but rather are applied to the scope object,这里跟以前同样,我仍是没理解。)
5、 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>