AngularJS--控制器(Controller)

點擊查看AngularJS系列目錄
轉載請註明出處:http://www.cnblogs.com/leosx/css


 

理解控制器

在AngularJS的控制器中,構造函數會有Scope參數。html

當一個控制器經過ng-controller指令鏈接到DOM上,Angular將實例化一個新的控制器對象,而後調用指定的控制器的構造函數。一個新的子做用範圍(scope)將被建立,並做爲一種可注入的參數傳遞給控制器​​的構造函數爲$scopeangularjs

若是控制器使用controller as語法附加到DOM上,那麼控制器實例將被分配給新的$scope範圍。而且多了一個和as同名的屬性,而後把本身指向這個屬性,就方便咱們訪問了。api

使用controller:app

1.初始化$scope對象。ide

2.爲$scope對象附加行爲。函數

錯誤的使用方式:測試

1.操做DOM -- 控制器中應該只包含業務邏輯。把業務邏輯放到控制器中,能夠顯著提升可測試性。Angualr大多數狀況下使用數據綁定和封裝指令來實現手動DOM操做。而不是直接在controller裏面操做DOM。ui

2.格式輸入 -- 應該使用Angular的表單控件,而不是用原生的表單控件。spa

3.filter過濾器 -- 應該使用Angular的filter來代替原生的過濾器。

4.跨控制器共享代碼或狀態 -- 應該使用Angular的服務來代替。

5.管理其餘組件的生命週期(例如,建立服務實例)。


 

$scope 對象的初始化

一般狀況下,當你建立一個應用程序,你都會須要初始化angular的$scope。一般狀況下,咱們在初始化$scope的時候,都是爲$scope附加一些屬性或者方法。該屬性包含視圖所使用的模型(由視圖中提出的模型)。全部$scope上的屬性,在controller中註冊的模板的DOM控件都是能夠訪問的。

下面的例子演示如何建立一個GreetingController,而且向$scope做用域範圍中增長了一個問候語屬性:

var myApp = angular.module('myApp',[]);

myApp.controller('GreetingController', ['$scope', function($scope) {
  $scope.greeting = 'Hola!';
}]);

咱們爲咱們的引用程序建立了一個AngularJS模塊 – myApp .而後咱們使用模塊的.controller()方法將控制器的構造函數模塊中去。

在這裏,咱們已經使用了內嵌的注入器明確指定了由Angualr提供的$scope服務的依賴。查看依賴注入的指南,瞭解更多信息。

咱們使用ng-controller 指令將controller綁定到DOM上。greeting 屬性會被綁定到咱們到模板上去:

<div ng-controller="GreetingController">
  {{ greeting }}
</div>

 

$scope上增長一個行爲

爲了在視圖中對事件做出反應或執行計算,咱們必需要讓$scope提供響應的功能/行爲。一般,咱們都是附加一個方法來提供這些功能的。附加以後,這些方法就能夠被 模板/視圖 調用。

下面的示例向一個控制器的$scope添加一個方法來實現翻倍:

var myApp = angular.module('myApp',[]);

myApp.controller('DoubleController', ['$scope', function($scope) {
  $scope.double = function(value) { return value * 2; };
}]);

 

一旦controller被附加到了DOM上,那麼這個double方法就能夠在Angularjs的模板中被調用了。

<div ng-controller="DoubleController">
  Two times <input ng-model="num"> equals {{ double(num) }}
</div>

正如本指南的概念部分所提到的,任何對象(或原函數)分配到的做用域範圍$scope成爲模塊module的一個屬性。任何被附加到$scope上到屬性或者方法,對於view或者模板(template)都是能夠訪問到的。而且能夠經過表達式或者ng-事件來調用(例如:ngClick)。

 

正確的使用controller

通常狀況下,一個控制器不該該試圖作太多操做。它應只該包含單個視圖所需的業務邏輯。

保持控制器乾淨單一的方法就是把那些和不屬於這個控制器的東西放到一個服務中去。而後經過在控制器中依賴注入這個服務,而後去使用服務所提供的方法。將會在本指南的依賴注入和服務節中討論。

 

簡單例子

文件一:index.html

<div ng-controller="SpicyController">
 <button ng-click="chiliSpicy()">Chili</button>
 <button ng-click="jalapenoSpicy()">Jalapeño</button>
 <p>The food is {{spice}} spicy!</p>
</div>

文件二:app.js

var myApp = angular.module('spicyApp1', []);

myApp.controller('SpicyController', ['$scope', function($scope) {
    $scope.spice = 'very';

    $scope.chiliSpicy = function() {
        $scope.spice = 'chili';
    };

    $scope.jalapenoSpicy = function() {
        $scope.spice = 'jalapeño';
    };
}]);

 

效果圖(本身去實現一下看看效果):

image

 

多層次的Scope示例

如今咱們來初步看一下將controller多層次的綁定在DOM上。當ng-controller指令建立了一個新的$scope,咱們要知道,這個$scope是繼承自上級$scope而來的(每一個module都會有一個$rootScope,第一級controller$scope將會繼承自這個$rootscope)。既然是繼承,那麼子集controller$scope就會包含了上級controller$scope全部的屬性和方法!關於更多的$scope相關的,請查閱相關章節。

來一個例子看看吧!

第一個文件:index.html

<div class="spicy">
  <div ng-controller="MainController">
    <p>Good {{timeOfDay}}, {{name}}!</p>

    <div ng-controller="ChildController">
      <p>Good {{timeOfDay}}, {{name}}!</p>

      <div ng-controller="GrandChildController">
        <p>Good {{timeOfDay}}, {{name}}!</p>
      </div>
    </div>
  </div>
</div>

 

第二個文件:app.css

div.spicy div {
  padding: 10px;
  border: solid 2px blue;
}

 

第三個文件:app.js

var myApp = angular.module('scopeInheritance', []);
myApp.controller('MainController', ['$scope', function($scope) {
  $scope.timeOfDay = 'morning';
  $scope.name = 'Nikki';
}]);
myApp.controller('ChildController', ['$scope', function($scope) {
  $scope.name = 'Mattie';
}]);
myApp.controller('GrandChildController', ['$scope', function($scope) {
  $scope.timeOfDay = 'evening';
  $scope.name = 'Gingerbread Baby';
}]);

 

效果圖以下:

image

請注意咱們是如何將ng-controller指令嵌套在咱們的模板當中的。上面的例子中,總共產生了四個scope。

一、root scope(每個module都會有一個$rootscope)

二、MainController 的scope,其中包含了timeOfDayname 屬性。

三、ChildController 的scope,它繼承了上一級的timeOfDay 屬性,而且重寫了上一級的name 屬性。

四、GrandChildController 的scope,它重寫了全部上級的timeOfDayname 屬性。

繼承方法和繼承屬性是同樣的。因此,上面的那些屬性也能夠換成一個返回字符串的方法,都是能夠的。

 

測試控制器(controller)

雖然有許多方法來測試一個控制器,可是推薦以下圖所示,注入$rootScope$controller的方式來測試:

控制器的定義:

var myApp = angular.module('myApp',[]);

myApp.controller('MyController', function($scope) {
  $scope.spices = [{"name":"pasilla", "spiciness":"mild"},
                   {"name":"jalapeno", "spiciness":"hot hot hot!"},
                   {"name":"habanero", "spiciness":"LAVA HOT!!"}];
  $scope.spice = "habanero";
});

控制器的測試:

describe('myController function', function() {

  describe('myController', function() {
    var $scope;

    beforeEach(module('myApp'));

    beforeEach(inject(function($rootScope, $controller) {
      $scope = $rootScope.$new();
      $controller('MyController', {$scope: $scope});
    }));

    it('should create "spices" 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');
    });
  });
});

 

若是你須要測試嵌套的控制器,你必須按照DOM結構層次去逐一建立對應的controller:

describe('state', function() {
    var mainScope, childScope, grandChildScope;

    beforeEach(module('myApp'));

    beforeEach(inject(function($rootScope, $controller) {
        mainScope = $rootScope.$new();
        $controller('MainController', {$scope: mainScope});
        childScope = mainScope.$new();
        $controller('ChildController', {$scope: childScope});
        grandChildScope = childScope.$new();
        $controller('GrandChildController', {$scope: grandChildScope});
    }));

    it('should have over and selected', function() {
        expect(mainScope.timeOfDay).toBe('morning');
        expect(mainScope.name).toBe('Nikki');
        expect(childScope.timeOfDay).toBe('morning');
        expect(childScope.name).toBe('Mattie');
        expect(grandChildScope.timeOfDay).toBe('evening');
        expect(grandChildScope.name).toBe('Gingerbread Baby');
    });
});
相關文章
相關標籤/搜索