ng-model trong AngularJS

Các bạn theo dõi các bài viết của mình đều thấy trong các ví dụ của mình dùng ng-model, vậy ng-model là gì và hoạt động như thế nào? Sau đây mình sẽ chỉ ra ng-model là gì, có nhiệm vụ gì, sử dụng như thế nào.

Ng-mode trong AngularJS?

Ng-model là một directive dùng để liên kết dữ liệu với client, một số người gọi nó là ngModel. Người ta thường dùng nó trong các form html để cho user nhập liệu. Chắc bạn còn nhớ ở các bài trước mình đã làm một số ví dụ với ng-model, ở các bài đó mình đã kết hợp ng-model với các directive khác để xây dựng các ứng dụng nho nhỏ.

Định nghĩa thì nói chính hơn là ng-model sẽ liên kết với thuộc tính scope sử dụng ngModelController (được khởi tạo và bởi ng-model). Ngoài ra nói 1 chút về ng-bin thì đây là directive sử dụng để liên kết dữ liệu với ng-model, mình sẽ có 1 bài nâng cao hơn về directive này.

Nhiệm vụ của ng-model

Trong angularJS thì ng-model có các nhiệm vụ sau : Liên kết view trong model và các directive khác như input, textarea, select. Cung cấp các thao tác validate dữ liệu Kiểm tra và thông báo lỗi cho user Thiết lập các css class và hiệu ứng thông báo trong thẻ HTML (ng-valid, ng-invalid, ng-dirty, ng-touched, ng-ungtouched) Ng-model sẽ liên kết với các giá trị được khai báo ví dụ {{email}}, trường hợp nếu không tồn tại thì nó sẽ được tạo ngầm và lưu vào scope. Nếu bạn khai báo ng-model=”something” thì khi chạy ứng dụng, trong $scope sẽ tồn tại một giá trị $scope.something. Vậy nên trong controller muốn xử lý gán giá trị cho model thì chỉ cần dùng $scope để thay đổi. Mình sẽ có ví dụ đề cập đến vấn đề này.

Danh sách các css được ng-model thêm vào

ng-valid: model is valid ng-invalid: model is invalid ng-valid-[key]: for each valid key added by $setValidity ng-invalid-[key]: for each invalid key added by $setValidity ng-pristine: the control hasn't been interacted with yet ng-dirty: the control has been interacted with ng-touched: the control has been blurred ng-untouched: the control hasn't been blurred ng-pending: any $asyncValidators are unfulfilled Để hiểu rõ hơn về ý nghĩa của từng class thì bạn có thể xem ví dụ ở bên dưới.

Ví dụ về ng-model trong angularJS

ng-pattern

Ví dụ: Xây dựng FORM và kiểm tra dữ liệu nhập vào input có phải là các chữ số hay không

<html>
    <head>
        <title>Angular JS Model</title>
        <script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular.min.js"></script>
        <script>
            angular.module('MyForm', [])
                    .controller('ExampleController', ['$scope', function($scope) {
            }]);
        </script>
        <style>
            .my-input {
                -webkit-transition:all linear 0.5s;
                transition:all linear 0.5s;
                background: transparent;
            }
            .my-input.ng-invalid {
                color:white;
                background: red;
            }
        </style>
    </head>
    <body ng-app="MyForm">
        <form name="testForm" ng-controller="ExampleController">
            <div>
              Chỉ được nhập số
            </div>
            <input ng-model="val" ng-pattern="/^\d+$/" name="anim" class="my-input" />
        </form>
    </body>
</html>

Bạn có thể xem demo tại đây https://jsfiddle.net/SonCheDinh/ye3sv4b9/ Bạn có thể thử nhập text hoặc chữ số vào ô input để thấy kết quả.

Trong đoạn code CSS mình đã định nghĩa lại hiệu ứng CSS cho class ng-invalid cho background màu đỏ:

<style>
    .my-input {
        -webkit-transition:all linear 0.5s;
        transition:all linear 0.5s;
        background: transparent;
    }
    .my-input.ng-invalid {
        color:white;
        background: red;
    }
</style>

Còn trong form HTML mình tạo một ng-model = "val", một pattern ng-pattern="/^\d+$/". khi chạy lên thì ngModel thấy có khai báo pattern nên dữ liệu nhập vào sẽ được validate bởi pattern này. Bây giờ bật firebug ở FF hoặc Inspect ở Chrome lên thì bạn sẽ thấy các class css mà ng-model tự thêm vào như sau: <input ng-model="val" ng-pattern="/^\d+$/" name="anim" class="my-input ng-pristine ng-valid ng-valid-pattern ng-touched">

Trong đó:

  • Class ng-valid là vì chúng ta chưa nhập dữ liệu nên trạng thái là valid, vì vậy class ng-valid được thêm vào.
  • Class ng-pristine là lúc mới chạy lên trạng thái là chưa nhập liệu lần nào nên nó được thêm vào
  • Class ng-valid-pattern là do ta chưa nhập dữ liệu gì nên chuỗi pattern chưa được kiểm tra nên valid

Bây giờ bạn thử nhập chữ “dep trai 2017” thì kết quả sẽ như hình trên, lúc này bạn soi firebug/inspect sẽ thấy có một số thay đổi: <input ng-model="val" ng-pattern="/^\d+$/" name="anim" class="my-input ng-touched ng-dirty ng-valid-parse ng-invalid ng-invalid-pattern">

Trong đó:

  • Class ng-dirty là do ta từng nhập dữ liệu rồi nên nó được thêm vào
  • Class ng-invalid là do trạng thái của input không đúng nên nó được thêm vào.
  • Class ng-invalid-pattern là do pattern bị sai nên nó được thêm vào

Chú ý: Trạng thái class của các input là cho từng input, còn của form là được quyết định bởi toàn bộ các input, nghĩa là nếu toàn bộ các input trong form đúng thì form đó mới đúng, không tin bạn thử thêm một input như vậy nữa và nhập vào một cái đúng một cái sai và soi debug thử nhé.

Required

Required là một thuộc tính của HTML5 dùng để yêu cầu bắt buộc nhập dữ liệu. Ở trong AngularJS nếu bạn khai báo nó trong các thẻ input thì nó cũng được coi là một Directive của AngularJS. Ví dụ: Kiểm tra bắt buộc nhập dữ liệu vào thẻ input.

<html>
    <head>
        <title>Angular JS Model</title>
        <meta charset='utf8'/>
        <script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular.min.js"></script>
        <script>
            angular.module('MyForm', [])
                    .controller('ExampleController', ['$scope', function($scope) {
            }]);
        </script>
        <style>
            .my-input {
                -webkit-transition:all linear 0.5s;
                transition:all linear 0.5s;
                background: transparent;
            }
            .my-input.ng-invalid {
                color:white;
                background: red;
            }
        </style>
    </head>
    <body ng-app="MyForm">
        <form name="testForm" ng-controller="ExampleController">
            <h2>Vui lòng nhập dữ liệu vào</h2>
            <input ng-model="val" required name="anim" class="my-input" />
        </form>
    </body>
</html>

Bạn có thể xem demo tại đây để hiểu rõ hơn https://jsfiddle.net/SonCheDinh/xL01d2fp/ Và đây là kết quả

Nếu bạn không nhập gì thì nó sẽ bị mầu đỏ chính là do thuộc tính required. Bạn có thể bật firebug/inspect lên để xem các thay đổi của class. Lưu ý: Ngoài thuộc tính required trên ta có thể thay bằng ng-required ví dụ <input ng-model="val" ng-required='true' name="anim" class="my-input" />

Các directive validate khác

Bây giờ chúng ta sẽ cùng nhau làm một ví dụ về các directive khác, thông qua đó bạn sẽ hiểu rõ hơn. Ví dụ: Cho người dùng nhập vào 2 số, validate cho nó và đồng thời hiển thị kết quả. Bước 1: Xây dựng form

<body ng-app="MyForm">
    <form name="calForm" ng-controller="ExampleController">
        <h2>{{message.title}}</h2>
        <h5>{{message.num1}}:</h5>
        <input ng-model="so_thu_nhat" ng-required='true' ng-pattern="/^[0-9]+$/" class="my-input" ng-keyup="show_result()" />
        <h5>{{message.num2}}:</h5>
        <input ng-model="so_thu_hai" ng-required='true' ng-pattern="/^[0-9]+$/" class="my-input" ng-keyup="show_result()" />
        <div style='{{styleresult}}'>
            {{message.phep_cong}} {{result.phep_cong}}<br/>
            {{message.phep_tru}}  {{result.phep_tru}}<br/>
            {{message.phep_nhan}} {{result.phep_nhan}}<br/>
            {{message.phep_chia}} {{result.phep_chia}}
        </div>
    </form>
</body>

Lúc này trông giao giện chả ra cái gì đâu.

Bước 2 : xây dựng các giá trị khởi tạo cho form

angular.module('MyForm', [])
.controller('ExampleController', ['$scope', function($scope) 
{
    // Khởi tạo giá trị ban đầu
    $scope.message = {
        title : 'Máy tính',
        num1 : 'Số thứ nhất',
        num2: 'Số thứ Hai',
        phep_cong : "Cộng hai số:",
        phep_tru : "Trừ hai số:",
        phep_nhan : "Nhân hai số:",
        phep_chia : "Chia hai số:"
    };
    // vì ban đầu chưa nhập gì nên ẩn khung kết quả
    $scope.styleresult = 'display:none';
 
}]);

Bước 3: Xử lý sự kiện ng-keyup. Nó giống onkeyup trong Javascript .Bạn tiếp tục thêm đoạn mã Javascript sau bên dưới đoạn code xây dựng giá trị ban đầu cho FORM

// Khi nhập các số vào các input thì gọi sự kiện này
    $scope.show_result = function()
    {
      // Nếu validate form đúng
      if ($scope.calForm.$valid){
        $scope.styleresult = 'display:block';
        $scope.result = {
          phep_cong : parseInt($scope.so_thu_nhat) + parseInt($scope.so_thu_hai),
          phep_tru : parseInt($scope.so_thu_nhat) - parseInt($scope.so_thu_hai),
          phep_nhan : parseInt($scope.so_thu_nhat) * parseInt($scope.so_thu_hai),
          phep_chia : parseInt($scope.so_thu_nhat) / parseInt($scope.so_thu_hai)
        };
      }
      // nếu validate form sai thì ẩn result
      else {
        $scope.styleresult = 'display:none';
      }
    };

Chú ý : Mình sử dụng tên của form để kiểm tra trạng thái của form có tên là calForm ($scope.calForm.$valid) Mình khai báo 2 ng-model ở hai input nên khi chạy ứng dụng 2 input này sẽ được tự thêm vào $scope, vì thế muốn sử dụng nó chỉ cần dùng cú pháp $scope.name ($scope.so_thu_nhat, $scope.so_thu_hai) Kết quả sẽ là như thế này

Tóm lại là qua bài này các bạn sẽ hiểu được Directive ng-model trong angularJS là gì, dùng như thế nào … Hẹn gặp lại ở bài sau.