Binding và Template Directive trong AngularJS (phần 1)

Directives

Directives là một trong những tính năng mạnh mẽ nhất của AngularJS. Mỗi một directive đại diện cho một chức năng gắn liền với DOM element. Các Directives có khả năng thực thi các phương thức, định nghĩa các hành vi, các đối tượng $scope,điều khiển DOM và nhiều việc khác nữa.

Khi các ứng dụng AngularJS được khởi động và biên dịch, Angular bắt đầu đi qua DOM tree, phân tích HTML vả tìm kiếm các directives bên trong. Angular sẽ tiến hành thu thập, sắp xếp và chạy các chức năng directives theo thứ tự ưu tiên.

1. Data binding Directives

Hạng mục đầu tiên được xây dựng trong directives đó chính là data binding, đó là một trong những tính năng biến AngularJS từ một template package trở thành một framework phát triển web đầy đủ. Dưới đây là liệt kê những directives dùng trong data binding

Untitled presentation (2).png

Tất cả các data binding directives được liệt kê bên trên đều có thể sử dụng như một attributes hoặc class, thậm chí một số khác có thể sử dụng để tùy chỉnh thành phần HTML.

Cách sử dụng:

  <span ng-bind="users.length"></span>

Trong trường hợp này directive được quy định như tên một attribute, thiết lập giá trị cho ng-bind giống như thiết lập giá trị cho attribute đó.

Một số nhà phát triển không thích cách sử dụng này vì việc sử dụng các attribute tự định nghĩa đôi khi sẽ gây phát sinh lỗi do hệ thống kiểm soát phiên bản không cho phép nội dung HTML được cập nhật cùng với nonstandard attributes. Nếu không muốn hoặc không thể sử dụng custom attributes, chúng ta có thể thiết lập directives sử dụng standard class attributes:

  <span class="ng-bind: users.length"></span>

Lúc này giá trị của class attribute là tên của directive, sau dấu ':' là thiết lập cho directive. Tương tự như cách dùng custome attribute, nó sẽ tạo ra one-way data binding bên trong thuộc tính users.length.

1.1 One-way Binding

Angular hỗ trợ 2 kiểu data binding. Thứ nhất là one-way binding, có nghĩa là một giá trị được lấy từ model rồi chèn vào một phần tử HTML. Mỗi khi giá trị trong model thay đổi thì ngay lập tức phần tử HTML sẽ cập nhật và hiển thị giá trị mới. ng-bind directives chịu trách nhiệm tạo ra one-way data bindings nhưng nó hiếm khi được sử dụng trực tiếp bởi AngularJS cũng sẽ tạo ra 1 one-way binding bất cứ khi nào gặp kí hiệu {{}} bên trong HTML Ví dụ tạo one-way data binding:

    <!DOCTYPE html>
    <html ng-app="demoApp">
      <head>
         <title>Directives</title>
         <script src="angular.js"></script>
         <link href="bootstrap.css" rel="stylesheet" />
         <link href="bootstrap-theme.css" rel="stylesheet" />
         <script>
          angular.module("demoApp", [])
          .controller("defaultCtrl", function ($scope) {
            $scope.todos = [
            { action: "Get groceries", complete: false },
            { action: "Call plumber", complete: false },
            { action: "Buy running shoes", complete: true },
            { action: "Buy flowers", complete: false },
            { action: "Call family", complete: false }];
          });
         </script>
      </head>
      <body>
        <div id="todoPanel" class="panel" ng-controller="defaultCtrl">
          <h3 class="panel-header">To Do List</h3>
          <div>There are {{todos.length}} items</div>
          <div>
            There are <span ng-bind="todos.length"></span> items
          </div>
          <div ng-bind-template="First: {{todos[0].action}}. Second: {{todos[1].action}}"></div>
          <div ng-non-bindable>AngularJS uses {{ and }} characters for templates</div>
       </div>
      </body>
    </html>

Trong ví dụ trên {{todos.length}} và ng-bind="todos.length" là tương đương

<div>There are {{todos.length}} items</div>

Đây là cách đơn giản nhất để tạo các data binding, dễ đọc và phù hợp với nội dung HTML.

There are <span ng-bind="todos.length"></span> items

Trường hợp này sử dụng ng-binding directive, cho ra kết quả tương tự như cách trên nhưng yêu cầu chèn thêm thẻ <span>

1.2 Two-way Data Binding

    <!DOCTYPE html>
    <html ng-app="demoApp">
      <head>
         <title>Directives</title>
         <script src="angular.js"></script>
         <link href="bootstrap.css" rel="stylesheet" />
         <link href="bootstrap-theme.css" rel="stylesheet" />
         <script>
          angular.module("demoApp", [])
          .controller("defaultCtrl", function ($scope) {
            $scope.todos = [
            { action: "Get groceries", complete: false },
            { action: "Call plumber", complete: false },
            { action: "Buy running shoes", complete: true },
            { action: "Buy flowers", complete: false },
            { action: "Call family", complete: false }];
          });
         </script>
      </head>

      <body>
        <div id="todoPanel" class="panel" ng-controller="defaultCtrl">
          <h3 class="panel-header">To Do List</h3>
          <div class="well">
            <div>The first item is: {{todos[0].action}}</div>
          </div>
          <div class="form-group well">
            <label for="firstItem">Set First Item:</label>
            <input name="firstItem" class="form-control" ng-model="todos[0].action" />
          </div>
        </div>
      </body>
    </html>

Trong ví dụ này sử dụng cả one-way binding và two-way binding directive, trong đó binding đầu tiên dùng one-way binding để hiển thị dữ liệu được khai báo trong controller. Binding thứ 2 dữ liệu được lấy từ input element

<input name="firstItem" class="form-control" ng-model="todos[0].action" />

Có nghĩa là two-way bindings chỉ áp dụng đối với các phần tử cho phép người dùng điền dữ liệu như input, textarea, và select box. ng-model directive sẽ nhận những thay đổi nội dung của các element tương ứng sau đó cập nhật vào data model.

Tóm lại bản chất của two-way binding là AngularJS sử dụng các sự kiện của Javascript để tiếp nhận những thay đổi của yếu tố đầu vào (input) rồi truyền những thay đổi này thông qua $scope service để rồi đồng bộ giá trị đó ở khắp phạm vi sử dụng.

2 Template Directives

Data binding là tính năng cốt lõi của AngularJS, nhưng bản thân nó cũng có giới hạn nhất định. Một ứng dụng web hay bất cứ ứng dụng nào khác cũng đều có xu hướng gom những đối tượng có chung đặc tính hay phân loại nhóm đối tượng có đặc tính khác nhau. May mắn thay AngularJS bao gồm tập hợp các directives có thể sử dụng để tạo các phần tử HTML bằng cách sử dụng các template. Điều này khiến cho việc xử lý data collection hay thêm logic vào một template trở nên dễ dang hơn.

2.1 Generating Elements Repeatedly

Một trong những chức năng phổ biến nhất trong view đó là liệt kê những phần tử có nội dung giống nhau từ một mảng dữ liệu. Trong AngularJS điều này được thực hiện với ng-repeat

    <!DOCTYPE html>
    <html ng-app="demoApp">
      <head>
         <title>Directives</title>
         <script src="angular.js"></script>
         <link href="bootstrap.css" rel="stylesheet" />
         <link href="bootstrap-theme.css" rel="stylesheet" />
         <script>
          angular.module("demoApp", [])
          .controller("defaultCtrl", function ($scope) {
            $scope.todos = [
            { action: "Get groceries", complete: false },
            { action: "Call plumber", complete: false },
            { action: "Buy running shoes", complete: true },
            { action: "Buy flowers", complete: false },
            { action: "Call family", complete: false }];
          });
         </script>
      </head>

      <body>
       <div id="todoPanel" class="panel" ng-controller="defaultCtrl">
        <h3 class="panel-header">To Do List</h3>
        <table class="table">
          <thead>
            <tr>
              <th>Action</th>
              <th>Done</th>
            </tr>
          </thead>
          <tbody>
            <tr ng-repeat="item in todos">
              <td>{{item.action}}</td>
              <td>{{item.complete}}</td>
            </tr>
          </tbody>
        </table>
       </div>
      </body>
    </html>

Đây là cách đơn giản và phổ biến nhất khi sử dụng ng-repeat. Định dạng cơ bản sử dụng trong ng-repeat directives đó là "<variant> in <source>". Source là đối tượng hoặc mảng được định nghĩa trong controller $scope, directives lặp các đối tượng trong mảng tạo ra các instance và content.

    <tr ng-repeat="item in todos">
     <td>{{item.action}}</td>
     <td>{{item.complete}}</td>
    </tr>

Lặp với các thuộc tính của object

<table class="table">
  <thead>
    <tr>
      <th>Action</th>
      <th>Done</th>
    </tr>
  </thead>
  <tbody>
    <tr ng-repeat="item in todos">
      <td ng-repeat="prop in item">{{prop}}</td>
    </tr>
  </tbody>
</table>

Trường hợp lặp với Data Object Keys

<tr ng-repeat="item in todos">
   <td ng-repeat="(key, value) in item">
    {{key}}={{value}}
   </td>
</tr>

(còn tiếp ...)