12/08/2018, 15:25

Sự kế thừa của scope trong AngularJS

Trong angularJS, một scope con luôn kế thừa mọi thứ từ scope cha(trường hợp ngoại lệ là khi sử dụng thuộc tính isolate trong directives để tạo ra một directive cô lập không kế thừa từ nguyên mẫu). Sự kế thừa trong scope rất đơn giản và thường chúng ta không cần biết rõ quá trình gì đang xảy ra cho ...

Trong angularJS, một scope con luôn kế thừa mọi thứ từ scope cha(trường hợp ngoại lệ là khi sử dụng thuộc tính isolate trong directives để tạo ra một directive cô lập không kế thừa từ nguyên mẫu). Sự kế thừa trong scope rất đơn giản và thường chúng ta không cần biết rõ quá trình gì đang xảy ra cho đến khi chúng ta cần ràng buộc kiểu scope dữ liệu 2 chiều để định nghĩa scope cha từ scope con.

Trong phần này chúng ta sẽ cùng tìm hiểu sự kế thừa scope với những directive có sẵn của AngularJs như: ng-repeat, ng-include, ng-switch, ng-view, ng-controller, directive với scope: true, directive với transclude: true. Và theo mặc định các directives sẽ không tạo scope mới (scope: false).

  • ng-include: Chúng ta có một controller với các scope
$scope.myPrimitive = 50;
$scope.myObject    = {aNumber: 11};

và các đoạn html

<script type="text/ng-template" id="/template1.html">
    <input ng-model="myPrimitive">
</script>
<div ng-include src="'/template1.html'"></div>

<script type="text/ng-template" id="/template2.html">
    <input ng-model="myObject.aNumber">
</script>
<div ng-include src="'/template2.html'"></div>

Từng ng-include sẽ tao ra một scope con, kế thừa các đặc tính của cha. Khi chúng ta đánh 1 giá trị vào ô input đầu tiên, thì scope con sẽ lấy giá trị của scope mới và che đi thuộc tính của parent scope có cùng tên và đây không phải là kết quả chúng ta mong muốn. Nêu như chúng ta nhập giá trị vào ô thứ 2 trên giao diện, thì không bị như trên, bởi template2.htm bind ra một thuộc tính của 1 object, sự kế thừa nguyên mẫu sẽ được kích hoạt khi ngModel tìm kiếm đối tượng myObject - nó tìm thấy nó trong parent scope. Chúng ta có thể viết lại templte đầu tiên sử dụng $$parent, nếu chúng ta không muốn thay đổi mô hình của chúng ta từ một nguyên thủy sang một đối tượng:

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

Đối với tất cả các scope(cả nguyên mẫu hay không), Angulart luôn theo dõi mối quan hệ giữa scope cha mẹ với scope con, thông qua các thuộc tính của scope như parent,parent, parent,childHead và $$childTail.

  • ng-switch: Scope trong ng-switch cách thức kế thừa hoạt động giống như ng-include. Vì vậy, nếu chúng ta cần dữ liệu 2 chiều liên kết với một nguyên thủy trong scope cha mẹ, hãy sử dụng $$arent, hoặc thay đổi model thành một đối tượng và sau đó liên kết với một thuộc tính của đối tượng đó. Điều này sẽ tránh cho scope con ẩn thuộc tính của scope cha.
  • ng-repeat: Cách thức hoạt động của ng-repeat có khác một chút so với các thành phần trên. Chúng ta có một controller như sau:
$scope.myArrayOfPrimitives = [ 11, 22 ];
$scope.myArrayOfObjects    = [{num: 101}, {num: 202}]

và đoạn mã html

<ul>
  <li ng-repeat="num in myArrayOfPrimitives">
     <input ng-model="num"></input>
   </li>
</ul>
<ul>
  <li ng-repeat="obj in myArrayOfObjects">
     <input ng-model="obj.num"></input>
   </li>
</ul>

Với từng vòng lặp, ng-repeat sẽ tạo ra các scope mới, được thừa hưởng nguyên mẫu từ các scope cha, cũng đồng thời gắn các giá trị trong các thành phần cho từng scope mới. Nếu item là cơ bản (như trong myArrayOfPrimitives), về cơ bản một bản sao của giá trị được gán cho thuộc tính scope mới. Thay đổi giá trị thuộc tính scope con sẽ không thay đổi các tham chiếu mảng gốc. Vì vậy, trong vòng ng-repeati ở trên, mỗiscope con có một thuộc tính num độc lập với mảng myArrayOfPrimitives. Vì vậy, nếu các item là một đối tượng, một tham chiếu đến đối tượng gốc được gán cho thuộc tính của scope mới. Thay đổi giá trị của thuộc tính scope con (như sử dụng ng-model, hay obj.num) sẽ làm thay đổi đối tượng tham chiếu của scope cha. Vì vậy, trong ng-repeat ở trên, chúng ta có:

  • ng-view: Cách thức làm việc tương tự như ng-include.
  • directives
  • default (scope: false) : Các directives sẽ không tạo ra một scope mới, do đó, không có thừa kế ở đây. Điều này rất dễ, nhưng cũng nguy hiểm bởi vì, một chỉ thị có thể nghĩ rằng nó đang tạo ra một thuộc tính trên scope mới, khi thực tế nó đang sử dụng thuộc tính hiện có. Đây không phải là sự lựa chọn tốt cho việc viết các directives được sử dụng như các thành phần tái sử dụng được.
  • scope: true: Các directives tạo ra một scope con mới mà các thuộc tính kế thừa từ scope cha. Nếu nhiều directives (trên cùng một phần tử DOM) yêu cầu một scope mới, chỉ có một scope con mới được tạo ra. Vì chúng có thừa kế nguyên mẫu "bình thường", điều này giống như ng-include và ng-switch, vì vậy hãy thận trọng với việc ràng buộc dữ liệu 2 chiều với các scope cha.
  • transclude: true: Các directives tạo ra một scope con "transcluded" mới, các thuộc tính được kế thừa từ scope cha.
0