2014年7月17日 星期四

AngularJS 教學 - factory method

factory 方法是 AngularJS Module 所提供的一個建立 Service 的方法 (Module.factory)

如果不知道什麼是 Service 的,可以先看看 AngularJS 教學 - Service

使用方式就是利用 Module 的 factory 方法,並傳入兩個參數

分別是 Service 的名稱以及一個能夠回傳 Service Object 的工廠方法 (Factory Function)

以下我列舉了一個範例

var demoApp = angular.module("demoApp", []);
demoApp.factory("echoService", function(){
    var echoCount = 0;
    return {
        echo: function(name){
            return console.log((echoCount++) + ", Your name is " + name);
        }
    };

});



上面的例子我利用 demoApp 這個 module 的 factory 方法,建立了一個名為 echoService 的 Service

可以注意到第2個參數我傳入的是一個 Factory Function,該 Factory Function 回傳了一個 Object(紅色部分)

而這個被回傳的 Object 包含了一個 echo 的方法。

也就是說 我透過了 Module.factory 建立了一個名為 echoService 的 Service,並對外提供了

一個 echo 的方法讓外部可以呼叫

當你定義完了一個 Service 之後,外部該如何使用這個 Service 呢?

我以一個 Controller 為例,如下所示

demoApp.controller("demoCtrl1", function($scope, echoService){
     $scope.name = "Allen";
     $scope.echo = function(){
         echoService.echo($scope.name);
     };

})
//.....
<div ng-controller="demoCtrl1">
      Name : <input type="text" ng-model="name"/><br/>
      <button ng-click="echo()">click</button>

</div>


上面程式中最重要的地方就是在定義 demoCtrl1 的時候,我在它的 Factory Function

的第2個參數傳入的 echoService

這表示了這個 demoCtrl1 需要依賴名為 "echoService" 這個服務,如果這個參數名稱打錯了,就會找不到

也就是說 AngularJS 會依照 "echoService" 這個名稱去找是否有一個註冊的 Service 名子叫做 echoService

如果有的話就會將該 Service Object 傳入給 demoCtrl1

以下是這個範例的完整程式

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" ng-app="demoApp">
     <head>
         <title>Examples</title>
         <script type="text/javascript" src="js/angular.min.js"></script>
         <script>
              var demoApp = angular.module("demoApp", []);
              demoApp.controller("demoCtrl1", function($scope, echoService){
                  $scope.name = "Allen";
                  $scope.echo = function(){
                       echoService.echo($scope.name);
                  };
             })
             demoApp.factory("echoService", function(){
               var echoCount = 0;
               return {
                    echo: function(name){
                        return console.log((echoCount++) + ", Your name is " + name);
                    }
               };
             });
         </script>
     </head> 
     <body>
         <div ng-controller="demoCtrl1">
              Name : <input type="text" ng-model="name"/><br/>
              <button ng-click="echo()">click</button>
         </div>
     </body>

</html>

可能會有很多人會有一個疑問就是,如果有另外其他的 Controller 或是任意其他的元件,也依賴這個 echoService 的話

那麼大家所依賴的 Service Object 會是同一個嗎?

答案是  "是的"!!

為什麼呢,這就跟 AngularJS 的依賴注入 (Dependency Injection) 有關了

簡言之,當有一個元件需要 echoService 的時候,AngularJS 會先檢查這個 Service Object

是否已經存在過了,如果已經存在就直接回傳,不會去執行你定義的 Factory Function

如果不存在,就會執行你定義的 Factory Function 以得到一個 Service Object

並將該 Service Object cache 起來,也就是說你所定義的 Factory Function 最多只會被執行一次

所以為了證明 echoService 物件是唯一的,你可以定義數個元件且都依賴 echoService

並觀察他的 echoCount

底下我額外再定義一個 Controller 來說明

<html xmlns="http://www.w3.org/1999/xhtml" ng-app="demoApp">
     <head>
         <title>Examples</title>
         <script type="text/javascript" src="js/angular.min.js"></script>
         <script>
              var demoApp = angular.module("demoApp", []);
              demoApp.controller("demoCtrl1", function($scope, echoService){
                  $scope.name = "Allen";
                  $scope.echo = function(){
                       echoService.echo($scope.name);
                  };
             }).controller("demoCtrl2", function($scope, echoService){
                  $scope.name = "Bob";
                  $scope.echo = function(){
                       echoService.echo($scope.name);
                  };
             });
             demoApp.factory("echoService", function(){
               console.log("Factory Function be executed...");
               var echoCount = 0;
               return {
                    echo: function(name){
                        return console.log((echoCount++) + ", Your name is " + name);
                    }
               };
             });
         </script>
     </head> 
     <body>
         <div ng-controller="demoCtrl1">
              Name : <input type="text" ng-model="name"/><br/>
              <button ng-click="echo()">click</button>
         </div>

         <div ng-controller="demoCtrl2">
              Name : <input type="text" ng-model="name"/><br/>
              <button ng-click="echo()">click</button>
         </div>
     </body>

</html>

可以打開 Console 介面觀察其結果

你會發現雖然有兩個 Controller 依賴 echoService

但是 Console 只會出現一次 "Factory Function be executed"

而且不管你是按下哪一個按鈕,Console 所 log 出來的 echoCount 都是不斷遞增的

證明了這兩個 Controller 所拿到的 Service Object 都是同一個的

下一篇再來介紹 Module.service

沒有留言:

張貼留言