標籤:
在Angular中,控制器(Controller)就是基於JavaScript的構造方法,主要用來構造模型並建立模型和視圖之間的資料繫結。控制器裡面定義了應用程式的邏輯和行為。
通過ng-controller指令可以將控制器和DOM綁定起來。Angular會用定義過的控制器建構函式執行個體化一個控制器對象,在Angular應用(module)啟動的時候,會建立一個根範圍, Angular執行個體化每個控制器時會建立一個新的子範圍並作為可注入參數($scope)注入到控制器的構造方法中.
在理解控制器作用的基礎上,我們應當按照約定使用控制器:
1. 初始化$scope.
2. 在$scope中增加應用的行為。
盡量避免在如下情境中使用控制器:
1.操作DOM - 控制器主要包含商務邏輯。 把視圖邏輯放到控制器中會嚴重影響代碼的可測試性。Angular已經將絕大部分接聽程式和DOM操作邏輯加以封裝在資料繫結和指令(directives)中。
2. 格式化輸入 - 盡量用angular form controls取代。
3. 格式化或者過濾輸出 - 考慮使用Angular的過濾器(filters).
4. 實現共用程式碼片段,或者管理多個控制器之間的狀態 - 考慮使用service組件來管理
5. 管理其他組件的生命週期(例如建立service組件執行個體)
初始化$scope對象的狀態
但建立一個應用時,我們通常需要通過設定$scope的屬性來初始化Angular $scope的狀態。 這些屬性(properties)包含了視圖模型。$scope的屬性在控制器所綁定的DOM範圍內的模板(template)是可見的。
例如:
Js代碼
1 var myApp = angular.module(‘myApp‘,[]); 2 myApp.controller(‘GreetingController‘, [‘$scope‘, function($scope) { 3 $scope.greeting = ‘Hola!‘; 4 }]);
這裡建立了一個‘myApp‘的應用模組,並定義了‘GreetingController’控制器,接下來我們通過ng-controller指令將控制器綁定到相應的div上:
Html代碼
1 <div ng-controller="GreetingController"> 2 {{ greeting }} 3 </div>
這樣我們就可以通過{{greeting}}運算式得到greeting屬性的值。
給Scope對象賦予行為
我們可以給scope對象添加方法,這樣就可以在綁定的視圖或者模板中調用這些方法來響應事件或者執行一些計算任務. 讓我們看下面的例子:
Js代碼
1 var myApp = angular.module(‘myApp‘,[]); 2 3 myApp.controller(‘DoubleController‘, [‘$scope‘, function($scope) { 4 $scope.double = function(value) { return value * 2; }; 5 }]);
這段JS代碼中,我們給scope添加了double方法,然後我們將控制器添加到DOM中:
Html代碼
1 <div ng-controller="DoubleController"> 2 Two times <input ng-model="num"> equals {{ double(num) }} 3 </div>
這樣我們就可通過運算式調用scope的double方法。正如我們在基本概念一節中講述的, 定義在scope中的屬性可以作為模型資料被綁定,同時定義在scope中的方法也可以被運算式或者ng事件指令調用,例如ngClick.
正確使用控制器
簡言之,控制器中一般只包含視圖相關的商務邏輯. 我們可以和視圖無關的代碼及公用代碼封裝在service中,通過在構造器中注入依賴的方式來使用services. 我們將會在稍後的章節中詳解依賴注入機制.
關聯控制器和Scope對象
我們可以通過ngController指令和$route service來關聯控制器和Scope對象.
接下來我們通過代碼範例協助大家更好地理解Angular控制器的工作原理。我們將建立一個簡單的app包含三個部分:
1. 一個模板(template) 包含了一個訊息和兩個按鈕。
2. 一個模型(Model)包含一個名叫spice的屬性。
3. 一個控制器包含了兩個方法設定spice的值。
template code (index.html)
Html代碼
1 <div ng-controller="SpicyController"> 2 <button ng-click="chiliSpicy()">Chili</button> 3 <button ng-click="jalapenoSpicy()">Jalapeño</button> 4 <p>The food is {{spice}} spicy!</p> 5 </div>
app.js(定義了控制器)
Js代碼
1 var myApp = angular.module(‘spicyApp1‘, []); 3 myApp.controller(‘SpicyController‘, [‘$scope‘, function($scope) { 4 $scope.spice = ‘very‘; 5 6 $scope.chiliSpicy = function() { 7 $scope.spice = ‘chili‘; 8 }; 10 $scope.jalapenoSpicy = function() { 11 $scope.spice = ‘jalapeño‘; 12 }; 13 }]);
我們可以看到,模板中的訊息通過運算式綁定到spice屬性,spice被初始化為"very", 隨後我們有通過ng-click綁定了scope中的兩個方法,分別修改了spice的值, 但我們點擊按鈕時,訊息會被自動重新整理。
初始化頁面:
點擊Chili後, 訊息自動更新:
讓我們總結一下以上執行個體:
1. Angular通過ng-controller隱式的給模板建立了一個範圍(scope),這個範圍被SpicyController擴充。
2. SpicyController是一個普通的JavaScript函數。通常Controller名字首字母大寫,以Controller為尾碼。
3. 通過給$scope裡面的屬性賦值來建立或者更新模型。
4. Controller的方法可以直接定義為$scope的方法。
5. 可以在與控制器關聯的<div>以及子項目中通過模板中的運算式以及ng事件指令存取控制器的方法和屬性。
執行個體 二:為控制器方法添加參數, 參數可以引用model
Html代碼
1 <div ng-controller="SpicyController"> 2 <input ng-model="customSpice"> 3 <button ng-click="spicy(‘chili‘)">Chili</button> 4 <button ng-click="spicy(customSpice)">Custom spice</button> 5 <p>The food is {{spice}} spicy!</p> 6 </div> Java代碼
1 var myApp = angular.module(‘spicyApp2‘, []); 3 myApp.controller(‘SpicyController‘, [‘$scope‘, function($scope) { 4 $scope.customSpice = "wasabi"; 5 $scope.spice = ‘very‘; 7 $scope.spicy = function(spice) { 8 $scope.spice = spice; 9 }; 10 }]); 11
在這個例子中我們注意到ng-click綁定的方法中添加了參數, 參數為模型spice的值, 同時輸入文字框也綁定到spice屬性,但在輸入文字框裡面鍵入spice的值,點擊‘Custom Spice’ 按鈕, message中spiced的值會被替換成文字框中的值。
執行個體三: 範圍的繼承關係
我們可以把控制器關聯到不同的DOM層級。由於ng-controller指令會自動建立子範圍,所以範圍也有相應的層級關係。子範圍中可訪問上級範圍中的屬性和方法,上級範圍的同名屬性和方法將被子範圍隱藏。 讓我們結合代碼來理解:
index.html
Index.html代碼
1 <div class="spicy"> 2 <div ng-controller="MainController"> 3 <p>Good {{timeOfDay}}, {{name}}!</p> 4 5 <div ng-controller="ChildController"> 6 <p>Good {{timeOfDay}}, {{name}}!</p> 7 8 <div ng-controller="GrandChildController"> 9 <p>Good {{timeOfDay}}, {{name}}!</p> 10 </div> 11 </div> 12 </div> 13 </div>
app.css
App.css代碼
1 div.spicy div { 2 padding: 10px; 3 border: solid 2px blue; 4 }
app.js
App.js代碼
1 var myApp = angular.module(‘scopeInheritance‘, []); 2 myApp.controller(‘MainController‘, [‘$scope‘, function($scope) { 3 $scope.timeOfDay = ‘morning‘; 4 $scope.name = ‘Nikki‘; 5 }]); 6 myApp.controller(‘ChildController‘, [‘$scope‘, function($scope) { 7 $scope.name = ‘Mattie‘; 8 }]); 9 myApp.controller(‘GrandChildController‘, [‘$scope‘, function($scope) { 10 $scope.timeOfDay = ‘evening‘; 11 $scope.name = ‘Gingerbread Baby‘; 12 }]);
運行結果:
我們注意到這裡我們實現了三個控制器: MainController, ChildController, GrandChildController,並在不同級的div中被關聯,Angular將產生四個範圍:
1. root scope即根範圍
2. MainController的範圍, 包括了timeOfDay和name屬性。
3. ChildController的範圍, 繼承了MainController的timeOfDay屬性,覆蓋了MainController的name屬性。
4. GrandChildController的範圍,分別從MainController範圍繼承了timeOfDay屬性, 覆蓋了上一層範圍的name屬性。
範圍中的方法原理同上, 這裡就不一一詳解。
AngularJS講義-控制器