2014年11月15日 星期六

AngularJS Scope:use ng-include

此篇文章因為一開始使用mac pages製作,後來再轉成html輸出至此,格式很亂(因為我還不太會用pages),因此code的部分皆使用純文字貼上,請見諒

Scope:use ng-include
此篇所有測試sourceuse hg-include

angularJsScope繼承概念在一般情形下是很直觀的,然而在2-way-data binding的primitive情況下有些必須注意,以下來做些ng-include的小測試:

首先我們準備檔案index.html 
<!DOCTYPE html>
<html ng-app="myApp">
<!-- class="show-scope-demo"-->
<head>
  <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.0/angular.min.js"></script>
  <link rel="stylesheet" href="style.css">
  <script src="script.js"></script>
</head>


<body ng-controller="scopeCtrl as ctrl">
  <h1>Hello!Scope</h1>

  use myPrimitive: <input ng-model="myPrimitive">
  use myObject.aNumber: <input ng-model="myObject.aNumber">

  <p>myPrimitive:{{myPrimitive}}</p>
  <p>myObject.aNumber:{{myObject.aNumber}}</p>

</body>


再來準備script.js 

var app = angular.module('myApp',[]);
app.controller('scopeCtrl' ,['$scope', function($scope){
  $scope.myPrimitive = 50;
  $scope.myObject    = {aNumber: 11};
  
  
  $scope.setMyPrimitive = function(value) {
      $scope.myPrimitive = value;
  }

}]);
執行測試:

  1. 當一開始載入後,一切如我們所想,兩個input輸入框與下方顯示都很完美的反應我們設定的初始值:
  2. 接下來我們試驗者改變兩個輸入框,將它們各自改變為2266,一切如我們預期般執行 

此時內部的假想scope如下:
 




接下來我們試驗使用ng-include方式,首先新增tpl1.html 

myPrimitive:
<input ng-model="myPrimitive">

<br>

再新增tpl2.html 


myObject.aNumber:<input ng-model="myObject.aNumber">

變更原先index.htmlbody部分): 


<body ng-controller="scopeCtrl as ctrl">
  <h1>Use ng-include</h1>

  <div ng-include src="'tpl1.html'"></div>
  <div ng-include src="'tpl2.html'"></div>

  <p>myPrimitive:{{myPrimitive}}</p>
  <p>myObject.aNumber:{{myObject.aNumber}}</p>

</body>

準備完畢,再一次執行測試:

  1. 當一開始載入後,一切如我們所想,兩個input輸入框與下方顯示都很完美的反應我們設定的初始值:
  2. 然而,這次我們一樣改變兩個輸入框,將它們各自改變為2266,卻發生了如下的情況
     

第一個myPrimitive沒有如果們預想的變更成功,這是怎麼一回事?
首先,我們知道使用ng-include會增加新的scope,因此一開始(初始載入後)的內部結構如下:



此時除了原先的RootScopeParentScope以外,又多了兩個ChildScope,分別為ng-include=‘tpl1.html’ng-include=‘tpl12.html’所產生。

而當我們變更輸入框的數值的時候,輸入框2(myObject.aNumber)還是維持與之前一樣的方式,參考至$parent.myObject.aNumber並且更改了他;然而輸入框1(myPrimitive)就不是這麼一回事了,他首先確認所屬的ChildScope1是否擁有myPrimitive這個變數,發現沒有,此時並不會如我們預想般自動去尋找$parent.myPrimitive,而是直接在ChildScope1下建立了myPrimitive,並且assign新值:22,因此目前內部結構變更如下: 

以上的問題全部都不是AngularJS才有的,屬於AngularJS的只有使用ng-include,建立了新scope;而不如我們預想般尋找$parent.myPrimitive並且變更而是產生新的myPrimitive則是JavascriptPrototypal Inheritance的概念(請參考連結文章,有很詳盡的說明)。

那麼如何去變更$parent.myPrimitive呢?有以下兩種方式:
  1. 一定使用關鍵字$parent
  2. 使用function()
以下我們繼續變更code測試上面兩個方式,首先測試第一種方式:使用$parent

變更tpl1.html

myPrimitive:
<input ng-model=“$parent.myPrimitive">

<br>

測試,變更輸入框為2266

執行成功!接下來測試第二種方式:使用function()
變更tp1.html


myPrimitive:
<input ng-model="myPrimitive">
<button ng-click="setMyPrimitive(myPrimitive)">$scope.setMyPrimitive()</button>

<br>

變更script.js


var app = angular.module('myApp',[]);
app.controller('scopeCtrl' ,['$scope', function($scope){
  $scope.myPrimitive = 50;
  $scope.myObject    = {aNumber: 11};
  
  $scope.setMyPrimitive = function(value) {
      $scope.myPrimitive = value;

  }

注意在這邊tpl1.html中的<input ng-model=“myPrimitive”>不是使用$parent.myPrimitive
開始測試!首先變更為2266



因為沒有使用方法1$parent.myPrimitive 因此myPrimitive如上所說一樣維持50 
這時我們按下<button>,呼叫$scope.setMyPrimitive(),確實變更成我們要的22了!