AngularJs Understanding the Controller Component_AngularJS

來源:互聯網
上載者:User

在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的資料整理,後續繼續補充相關資料,謝謝大家的支援!

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.