AngularJS (11) $http.get + templateUrl + scope 讀檔後匯入樣版

本篇完整程式碼請看Plunkr


我們在前一篇也說過,控制器可以定義值,再透過它範疇內的宣告標籤傳值到樣版。範疇的大致概念如下:

<div ng-controller="某控制器">
    <宣告標籤></宣告標籤> 
</div>

而樣版就像是句型一樣,讓我們可以餵值進去。

但是,如果餵進去的數值很多時,有沒有可能用讀檔的方式把大量的值傳給樣版呢?答案是可以。

大致解法是,先用$http.get()讀變數檔,再透過宣告標籤的templateUrl、scope將$http.get()的值餵給樣版。這麼說有點籠統(掩面),我們來看實例吧。


實例

今天你有了六個朋友的資訊,人名、地址,希望把他們照某個樣版顯示。

Lily Hualien
Ihc TsiongHua
Suisui2 Hualien
Suisui Hualien
Piggu Hualien
Chhueh TsiongHua

I'm ________, and I come from ________. 這是你想要的樣版。

朋友資訊那麼多,而且以後還會一直增加新好友,你當然就不希望把朋友資訊寫死在script,以免不容易維護程式。所以,最好的解法就是把你朋友的資料寫在一個文字檔,並用script去讀取它。


朋友資訊.txt

Lily Hualien
Ihc TsiongHua
Suisui2 Hualien
Suisui Hualien
Piggu Hualien
Chhueh TsiongHua

template.html

I'm {{friendName}}, and I come from {{friendAddr}}.<br/>

它存了句型I'm ________, and I come from ________.

人名和地址的填空處用樣版變數friendName,friendAddr表示。


JS 第一步:在控制器用$http.get()讀檔

要能夠顯示朋友的資料,當然首要做的就是讀出朋友資訊.txt的值,存到某個陣列變數內。作法如下

app = angular.module("app1",[]);

app.controller('NameController', ['$scope', '$http', function($scope, $http) {
    $scope.list = [];
    $http.get('namelist.txt').success(function(data){
      angular.forEach(data.split('\n'), function(line, ind){
        var words = line.split(' ');
        console.log(words);
        $scope.list.push({'name': words[0],
                         'addr': words[1]});
      });
    });//end $http
}]);

一開始,為了用$http.get()讀檔,['$http',...]讓控制器可以使用angularJS的$http服務。
app.controller('NameController', ['$scope', '$http', function($scope, $http) {

為了待會存入一組組朋友的名字和地址,我們初始化了一個空的list陣列變數。
$scope.list = [];
並且希望,待會做完讀檔後,list會像這樣
$scope.list = [{名字1, 地址1},{名字2, 地址2},...,{名字N, 地址N}];

確定好要得到的list格式後,我們用$http.get().success()寫明讀檔後要接著執行什麼事情。
$http.get('朋友資訊.txt').success(function(data){
而.success()裡的data=
Lily Hualien\n
Ihc TsiongHua\n
Suisui2 Hualien\n
Suisui Hualien\n
Piggu Hualien\n
Chhueh TsiongHua\n
但是和我們想要在控制器得到的不太一樣
$scope.list = [{名字1, 地址1},{名字2, 地址2},...,{名字N, 地址N}];

所以我們要在.success()裡頭寫個parser,從data的換行字元、空白字元分割出一組組人名和地址。

angular.forEach(data.split('\n'), function(line, ind){
  var words = line.split(' ');
  $scope.list.push({'name': words[0],
                    'addr': words[1]});
});

完成上述的所有步驟後,我們得到
$scope.list = [ 
   {name:"Lily", addr:"Hualien"}, {name:"Ihc, addr:"TsiongHua"},
   {name:"Suisui2", addr:"Hualien"}, {name:"Suisui", addr:"Hualien"},
   {name:"Piggu", addr:"Hualien"}, {name:"Chhueh", addr:"TsiongHua"} 
];

JS 第二步:新增宣告標籤

因為我們要連結控制器的$scope.list到樣版變數,所以要寫宣告標籤。

app.directive("myInfo", function(){
  return {
    restrict:'E',
    templateUrl:'template.html',
    scope: {
        friendName: '=infoName',
        friendAddr: '=infoAddr'
    }
  };
});

我們定義了一個宣告標籤,叫做myInfo
app.directive("myInfo", 

指定myInfo是自定元素,所以待會在網頁使用myInfo時可以寫成標籤<my-info>
restrict:'E',

myInfo的任務是,連結樣版,所以需要用templateUrl參數。
templateUrl:'template.html',

myInfo能夠連結樣版後,為了在網頁時,控制器可以透過<my-info>傳值給樣版,所以我們用scope參數新增兩個屬性。
scope: {
    friendName: '=infoName',
    friendAddr: '=infoAddr'
}
friendName 和 friendAddr 是樣版的填空處的變數。還記得我們的樣版嗎?
I'm {{friendName}}, and I come from {{friendAddr}}.<br/>

infoName 和 infoAddr 則是我們幫宣告標籤<my-info>新增的屬性。有什麼用處?留著這個疑問,先往下看網頁的寫法。


index.html

<body ng-app="app1">
   <div ng-controller="NameController">
     <my-info ng-repeat="man in list" info-name="man.name" info-addr="man.addr"></my-info>
   </div>
</body>

※infoName、infoAddr是js的寫法,在html要寫成info-name、info-addr


因為我們要從控制器的$scope.list,取出每一組人名地址丟給樣版,所以這麼寫

<my-info ng-repeat="man in list" info-name="man.name" 
            info-addr="man.addr">
</my-info>

其中有我們為<my-info>新增的屬性,info-name 和 info-addr。

它們在網頁中,被餵入一組組的人名和地址

info-name="man.name" info-addr="man.addr"

info-name 和 info-addr 得到值之後呢?

就要看我們在JS第二步新增的屬性:

scope: {
    friendName: '=infoName',
    friendAddr: '=infoAddr'
}

因此,info-name 和 info-addr 得到值之後,傳給樣版的friendName 和 firendAddr。


也就是,

在js定義了餵值給樣版的屬性,於是,在html把控制器的值餵給屬性,再透過屬性把值傳給樣版。


完成

I'm Lily, and I come from Hualien.
I'm Ihc, and I come from TsiongHua.
I'm Suisui2, and I come from Hualien.
I'm Suisui, and I come from Hualien.
I'm Piggu, and I come from Hualien.
I'm Chhueh, and I come from TsiongHua.

完整JS

var app = angular.module("app1",[]);
/*JS 第一步*/
app.controller('NameController', ['$scope', '$http', function($scope, $http) {
    //$scope.names = [];
    $scope.list = [];
    $http.get('namelist.txt').success(function(data){
      angular.forEach(data.split('\n'), function(line, ind){
        //$scope.names.push({name:line});
        var words = line.split(' ');
        $scope.list.push({'name': words[0],
                         'addr': words[1]});
      });
      console.log($scope.list);
        
    });//end $http
}]);

/*JS 第二步*/
app.directive("myInfo", function(){
  return {
    restrict:'E',
    scope: {
        friendName: '=infoName',
        friendAddr: '=infoAddr'
    },
    templateUrl:'template.html'
  };
});

附註

本例的朋友資訊是.txt檔,你當然也可以用*.json 或是任何喜歡的檔案格式,只是parser方式略有不同。

留言

這個網誌中的熱門文章

AngularJS (1) 宣告ng-app

href with relative url 在錨點使用相對路徑