Bài 06: Directive ng-model trong AngularJS

1. Ng-model trong AngularJS là gì ?

ng-model hay còn gọi là ngModel là một Directive dùng để liên kết dữ liệu với client, nghĩa là nó thường được dùng để cho người dùng nhập liệu nên ta hay sử dụng trong FORM html. Ở bài Scope trong Angularjs chúng ta cũng đã làm một ví dụ về ng-model mà có lẽ bạn vẫn còn nhớ, ở bài đó chúng ta đã kết hợp ng-model với ng-bind để xây dựng một ứng dụng nho nhỏ. Về định nghĩa ta nói chính xác hơn thì ng-model (ngModel) sẽ liên kết với một thuộc tính của Scope sử dụng ngModelController (được khởi tạo và  bởi ng-model). Còn về ng-bind tạm thời chúng ta có thể hiểu đơn giản dùng để liên kết dữ liệu với ng-model, còn nâng cao hơn chúng ta sẽ tìm hiểu ở một bài khác nhé. 

2. Ng-model trong AngularJS có nhiệm vụ gì?

ng_model có nhiệm vụ :

  • Liên kết View trong model và một số directives khác như input, textarea hoặc select.
  • Cung cấp các thao thác validate dữ liệu như kiểm tra kiểu dữ liệu có phải là số, là email, ...
  • Kiểm soát thông tin từ client nhập vào có hợp lệ hay không và xuất thông báo lỗi
  • Thiết lập các css class trong thẻ HTML (ng-valid, ng-invalid, ng-dirty, ng-pristine, ng-touched, ng-untouched) và các hiệu ứng thông báo
  • ng-model sẽ cố gắng liên kết với các giá trị được khai báo (ví dụ {{name}}), nếu không tồn tại thì nó sẽ được tạo ngầm và lưu vào Scope. Điều này có nghĩa rằng  nếu ta khai báo ng-model="somename" thì khi ứng dụng chạy lên trong $scope sẽ tồn tại một giá trị $scope.somename, nên trong controller ta muốn xử lý gán gái trị cho model thì chỉ cần dùng  $scope để thay đổi. Ở ví dụ cuối cùng của bài này chúng ta có đề cập đến vấn đề này đấy.

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

Sau đây là danh sách các class được ng-model tự thêm vào cho từng trường hợp cụ thể

  • 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

Thật sự tôi không biết dịch sao cho các class này nữa nên thay vì cố gắng rặn từng chữ thì chúng ta sẽ tìm hiểu dần, từ đó bạn sẽ hiểu được ý nghĩa của từng class. Như vậy sẽ tốt hơn là ngồi giải thích một loạt mà không hề có một ví dụ cụ thể nào. Trong các ví dụ dưới này chúng ta có tìm hiểu một số class phía trên đấy.

4. Các 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

XEM DEMO

<html>
    <head>
        <title>Angular JS Model</title>
        <script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.2.15/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">
            <input ng-model="val" ng-pattern="/^\d+$/" name="anim" class="my-input" />
        </form>
    </body>
</html>
Giao diện:

ng-model trong angular js

Các bạn thấy mình đã nhập dữ liệu là chữ s nên không đúng với yêu cầu, còn yêu cầu như thế nào thì ta sẽ mổ xẻ ví dụ đó nhé.

Trong đoạn code CSS dưới đây 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. Nếu bạn chưa biết về Pattern thì có thể tham khảo serie Regular Expression này nhé. Bây giờ bật firebug lên thì bạn sẽ thấy các class css mà ng-model tự thêm vào như sau:

tìm hiểu ng-partern

Trong đó:

  • Class màu xanh (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 màu tím (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 màu đỏ (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ữ s thì kết quả sẽ  như hình trên, lúc này bạn soi firebug sẽ thấy có một số thay đổi:

ví dụ ng-model và ng-model-partern

Trong đó:

  • Class màu đà (ng-dirty) là do ta từng nhập dữ liệu rồi nên nó được thêm vào
  • Class màu xanh (ng-invalid) là do trạng thái của input không đúng nên nó được thêm vào.
  • Class màu đỏ (ng-invalid-pattern) là do pattern bị sai nên nó được thêm vào
Lưu ý: 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

Nếu bạn đã học qua HTML5 thì 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 vào. 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.

XEM DEMO

<html>
    <head>
        <title>Angular JS Model</title>
        <meta charset='utf8'/>
        <script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.2.15/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 nhé</h2>
            <input ng-model="val" required name="anim" class="my-input" />
        </form>
    </body>
</html>
Giao diện:

required trong anguar

Lý do ta không nhập gì mà vẫn bị màu đỏ là do thuộc tính required đấy. Bây giờ bạn bật firebug lên và xem các class của nó thay đổi như thế nào nhé, tôi không làm thao tác này nữa vì mệt quá :D.

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 Directives validate khác

Còn rất nhiều nữa nhưng có lẽ mình sẽ trình bày trong bài tới, trong bài này chúng ta chỉ tìm hiểu 2 directive này cho bạn hiểu thôi nhé. Bây giờ ta sẽ làm một ví dụ nho nhỏ là làm chương trình máy tính tính tổng, hiệu, thương và tích của hai số nhé.

Ví dụ: Tạo 2 input và cho người dùng nhâp vào 2 số, validate bắt buộc nhập vào phải là số đồng thời xuất ra màn hình kết quả cộng trừ nhân chia của hai số đó.

XEM DEMO

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>
Giao diện lúc này như sau:

Lý do nó hiển thị y nguyên HTML ban đầu như vậy là ta chưa khai báo Angular bằng JS

Bước 2: Xây dựng giá trị ban đầu cho FORM

angular.module('MyForm', [])
.controller('ExampleController', ['$scope', function($scope) 
{
    // Khởi tạo giá trị ban đầu
    $scope.message = {
        title : 'Trò Chơi Tính Toán',
        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';

}]);
Giao diện lúc này như sau:

Bước 3: Viết code cho sự kiện ng-keyup (giống onkeyup trong Javascript) cho 2 input. 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';
    }
};
Tại bước này bạn cần chú ý:

  • Tôi 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)
  • Vì tôi 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)

Chạy lên bạn nhập vào hai số và kết quả sẽ là:

Toàn bộ code cho ví dụ này:

<html>
    <head>
        <title>Angular JS Model</title>
        <meta charset='utf8'/>
        <script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.2.15/angular.min.js"></script>
        <style>
            *{margin:0;}
            body{padding: 20px}
            .my-input {
                -webkit-transition:all linear 0.5s;
                transition:all linear 0.5s;
                background: transparent;
            }
            .my-input.ng-invalid {
                color:white;
                background: red;
            }
        </style>
        <script>
            angular.module('MyForm', [])
                    .controller('ExampleController', ['$scope', function($scope)
                {
                    // Khởi tạo giá trị ban đầu
                    $scope.message = {
                        title: 'Trò Chơi Tính Toán',
                        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ố:"
                    };
                    $scope.styleresult = 'display:none';

                    // 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';
                        }
                    };
                }]);
        </script>

    </head>
    <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>
</html>

5. Lời kết

Tới đây thật sự mình quá mỏi tay rồi không gõ thêm được chữ nào nữa nên có lẽ ta sẽ ngưng ở đây, bài tuy ngắn nhưng rất khó đấy nhé, nhất là ở ví dụ cuối cùng nó hơi khó cho những bạn mới tìm hiểu AngularJS. Hy vọng qua bài này bạn hiểu được Directive ng-model trong angularJS  là gì và cách sử dụng nó trong một số ví dụ ở trên. Bài tiếp theo chúng ta tiếp tục tìm hiểu một directive khác đó là ng-model-options.

Hãy để lại link bài viết gốc khi chia sẻ bài viết này, mình sẽ report DMCA với những website lấy nội dung mà không để nguồn hoặc copy bài với số lượng lớn.

Nguồn: freetuts.net

Profile photo of adminTheHalfHeart

TheHalfHeart

Có sở thích viết tuts nên đã từng tham gia viết ở một số diễn đàn, đến năm 2014 mới có điều kiện sáng lập ra freetuts.net. Sinh năm 90 và có 1 vợ 2 con, thích ca hát và lập trình.

ĐĂNG BÌNH LUẬN: Đăng câu hỏi trên Group Facebook để được hỗ trợ nhanh nhất.