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áong-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
Bài viết này được đăng tại [free tuts .net]
<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>
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>
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:
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:
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
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.
<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>
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.
<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ố đó.
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ý 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'; }]);
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 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.