2016年4月13日 星期三

AngularJS的$compile() - 動態增加DOM

在AngularJS中,會在瀏覽器對html解析成DOM後,先對AngularJS(ng-app)的進行編譯,給定scope後才會進行數據綁定。

但是如果是用例如JQuery等方式新增了新的DOM元素後,因為沒有用AngularJS編譯的關係,所以就算裡面有AngularJS的語法也不會呈現預期的結果。

例如像以下的例子:

HTML:
<div ng-app="myApp">
  <div id='DOMWrapper' ng-controller="myCtrl">
    <button ng-click='addDOM()'>Add DOM</button>
  </div>
</div>
Javascript:
var app = angular.module('myApp', []);
app.controller('myCtrl', ['$scope', '$compile', function($scope, $compile) {
	$scope.textOfDOM = 'Text show successfully';

  $scope.addDOM = function() {
    var DOMToAdd = $('<p>{{textOfDOM}}</p>');
    
    //Wrong code -- start
    $('#DOMWrapper').append(DOMToAdd);
    //Wrong code -- end    
    
    //Right code -- start
    //var linkOfDOMToAdd = $compile(DOMToAdd);
    //var nodeOfCompiledDOM = linkOfDOMToAdd($scope);
    //$('#DOMWrapper').append(nodeOfCompiledDOM);
    //Right code -- end
  };
}]);

 從結果中可以看到當按下"Add DOM"按鈕時,出現的字是 "{{textOfDOM}}",而不是我們預期的 "Text show successfully"。

這是因為要新增的DOM沒有被AngularJS編譯的關係,以下才是正確的程式碼:
HTML:
<div ng-app="myApp">
  <div id='DOMWrapper' ng-controller="myCtrl">
    <button ng-click='addDOM()'>Add DOM</button>
  </div>
</div>
Javascript:
var app = angular.module('myApp', []);
app.controller('myCtrl', ['$scope', '$compile', function($scope, $compile) {
	$scope.textOfDOM = 'Text show successfully';

  $scope.addDOM = function() {
    var DOMToAdd = $('<p>{{textOfDOM}}</p>');
    
    //Wrong code -- start
    //$('#DOMWrapper').append(DOMToAdd);
    //Wrong code -- end
    
    //Right code -- start
    var linkOfDOMToAdd = $compile(DOMToAdd);
    var nodeOfCompiledDOM = linkOfDOMToAdd($scope);
    $('#DOMWrapper').append(nodeOfCompiledDOM);
    //Right code -- end
  };
}]);
我們可以呼叫$compile()並把要編譯的DOM送進去當參數,它會返回一個 link 函式,呼叫 link 函式並把scope當作輸入參數,就可以將scope與被編譯的DOM產生連結,所以DOM就可以得到textOfDOM的值,link 函式會返回已經跟資料連結好的新的DOM物件,接著我們再把新的DOM物件用JQuery的語法放到 #DOMWrapper裡面,就可以正確的得到我們要的 "Text show successfully"了。

參考資料:

  1. 18.5. Compile的细节
  2. $compile

沒有留言 :

張貼留言