這篇來進一步介紹 Controller 內部吧,其實 Controller 相較於 Model 或是 Directives
都還要簡單許多,就目地面來說的確如此,畢竟 Controller 就只是個扮演
Model 與 View 之間的連結角色,提供資料以及服務給 View,並且處理一些 user action
但要掌握一整個 MVC 架構,Controller 仍然是一個關鍵的因素
以下先用一個類似於上一篇的範例來說明起:
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" ng-app="demoApp">
<head>
<title>Bootstrap
Examples</title>
<script type="text/javascript" src="js/angular.min.js"></script>
<script>
var
demoApp = angular.module("demoApp", []);
demoApp.controller("demoCtrl", function($scope){
$scope.name = "Allen";
$scope.getAge = function(name){
if(name
== "Allen") return
25;
else if(name
== "John") return
30;
else return 0;
};
});
</script>
</head>
<body>
<div ng-controller="demoCtrl">
Name: {{name}}
<br/>
Age: {{getAge(name)}}
</div>
</body>
</html>
上一篇說明到 $scope 的用途,可以注意到的是 我在 $scope 內定義了一個 getAge 函式
需要傳入名子才會回傳年齡,可以注意在 View 之中是怎呼叫的
直接在 Expression 內呼叫 getAge 函式,因為這個 Expression 是被 demoCtrl 所控管的
所以 AngularJS 會直接呼叫 demoCtrl 的 $scope 的 getAge 方法。
另外值得一提的是如果沒有在 $scope 內定義 getAge 也不會發生任何錯誤
頁面上也不會呈現 null 之類的,AngularJS 都會處理掉。
接下來說明一些比較關於設計及進階的問題
該如何定義一個 Controller 的範圍?
在一些簡單的教學中,可能會直接將 ng-controller 應用在 body 標籤
這其實就間接表示了這份HTML幾乎都由該 Controller 所負責
當然簡單的專案你可以這樣做,但是當你的視圖與邏輯越來越複雜之後
Controller 的責任就越來越多,且更難以維護,
因此基於單一職責原則以及模組化概念,最好還是將 Controller 依照視圖去切分
一個 View 可否重覆使用同一個 Controller?
答案是可以的,但是要注意的是
demoApp.controller("demoCtrl", function($scope){
$scope.name = "Allen";
$scope.getAge = function(name){
if(name == "Allen") return 25;
else if(name == "John") return 30;
else return 0;
};
});
上述的橘色 function 會被執行兩次 (如果你在視圖上定義兩次的話)
其實從 AngularJS 的官方文件可以得知 橘色那段 function 是一個 Factory Function
顧名思義就是,當需要使用一個 Controller 的時候就會執行這段 function
並且你會發現,兩個 Controller 的 $scope 的資料是並不會互通互相影響的
總之就是兩個 Controller 各自負責自己所控管的 View,互不干擾。例如:
<script>
var
demoApp = angular.module("demoApp", []);
demoApp.controller("demoCtrl1", function($scope){
$scope.count = 1;
$scope.add = function(){
$scope.count++;
};
});
</script>
<div ng-controller="demoCtrl1">
{{count}}
<button ng-click="add()">Increment</button>
</div>
<div ng-controller="demoCtrl1">
{{count}}
</div>
demoCtrl1 分別控制兩個不相干的 div,如果按下上面那個 button 只會增加
上面的 $scope.count 的值,下面的 $scope.count 的值並不會加1
Controller 可以巢狀(nested)表示嗎 ?
其實這我也不太會描述,官方說法是 "Scope Inheritance",如下
<div ng-controller="demoCtrl">
{{name}}
<div ng-controller="demoCtrl2">
{{name}}
<div ng-controller="demoCtrl3">
{{name}}
</div>
</div>
</div>
簡單說就是 Controller 所控管的 View 底下又有節點被其他的 Controller 控管
我們看一下程式的片段
<script>
var
demoApp = angular.module("demoApp", []);
demoApp.controller("demoCtrl1", function($scope){
$scope.name = "Controller
one";
}).controller("demoCtrl2", function($scope){
$scope.name = "Controller
two";
}).controller("demoCtrl3", function($scope){
$scope.name = "Controller
three";
});
</script>
在這種情況下,三個 Controller 的 $scope 都有定義 name 這個資料屬性
在 AngularJS 視為是繼承的關係:demoCtrl3 繼承 demoCtrl2,demoCtrl2 繼承 demoCtrl1
所以最後視圖呈現出來的結果,三個 name 的值都會不一樣,
因為 demoCtrl2 的 $scope.name 覆寫(override)掉了 demoCtrl1 的 $scope.name
而 demoCtrl3 則是覆寫掉了 demoCtrl2 的,簡言之在這種巢狀的情況下
就是一個繼承的概念,所有你所知的繼承觀念都會實現。
Controller 之間可以互相溝通嗎?
可以,透過 $rootScope 來達成,回到上上一個例子
如何按下上面那個 button 之後,下面的 Controller 的 $scope.count 能夠加1?
<script>
var
demoApp = angular.module("demoApp", []);
demoApp.controller("demoCtrl1", function($rootScope,
$scope){
$scope.count = 1;
$scope.add = function(){
$scope.count++;
$rootScope.$broadcast("countUpdate",
$scope.count);
};
$scope.$on("countUpdate", function
(event, param) {
$scope.count = param;
});
});
</script> 首先當聽到 button 按下並觸發 add function 時候,利用 $rootScope.$broadcast
觸發一個 "countUpdate" 的 Event 並把值當作參數傳入
並用 $scope.$on 接收這個 Event 並做後續動作,因此 View 不需要更動,
你會發現按下按鈕後 上下的 count 都會跟著加1了
接下一篇會再更詳細描述更多 Controller 的細節與陷阱
沒有留言:
張貼留言