Bài 07: Directive ng-model-options trong AngularJS

Bài trước chúng ta đã tìm hiểu một Directive rất quan trọng đó là ng-model trong AngularJS, và chúng ta cũng làm được khá nhiều ví dụ cho chủ đề ng-model này. Vậy để tiếp tục theo luồng serie thì trong bài này chúng ta sẽ tìm hiểu một Directive khác có liên quan mật thiết đến ng-model đó là ng-model-options trong AngularJS.

Tôi cũng xin nhắc lại nếu bạn là người mới tìm hiểu thì nên đọc kỹ những nội dung mà tôi viết chứ đừng coi ví dụ không thôi, như vậy bạn sẽ không hiểu được ý đồ của mình đâu.

1. ng-model-options là gì?

Dịch cái tên ra cũng đủ hiểu ý nghĩa của nó rồi, chúng ta thường sử dụng Directive ngModelOptions dùng để cấu hình một số thông số liên quan tới ng-model. Khi ứng dụng được chạy lên thì Directive này sẽ thực thi trước và sau đó ng-model mới được tạo.

Những thông số cấu hình này sẽ quyết định đến giá trị của model có được thay đổi và lưu vào $scope hay không? Nếu như lưu thì khi nào lưu? và cách lưu như thế nào? Tất cả những câu hỏi này chính là những ngModelOptions trong angular đấy;

2. Tìm hiểu $rollbackViewValue

Như các bạn thấy mỗi khi dữ liệu thay đổi thì sẽ được lưu vào trong $scope nên những thuộc tính nào đang được liên kết (ng-bind) với nó sẽ thay đổi theo, nhưng có những trường hợp ta muốn người dùng nhập nhưng không thay đổi nó trong $scope và ta cần lấy giá trị nguyên thủy này thì phải làm thế nào? Rất đơn giản, $roolbackViewValue sẽ giải quyết vấn đề này cho bạn. Vậy $rollbackViewValue chính là giá trị hiện tại của các thẻ input (model) được lưu trong mô hình của chúng ta.

Để gọi tới một view (giá trị thẻ input có khai báo model) nào đó trong form ta sẽ dùng cú pháp như sau trong controller:

$scope.formName.inputName.$rollbackViewValue;
Tại sao lại thông qua $scope? Câu trả lời mình cũng đã nhắc ở bài trước nay mình nhắc lại luôn. Lý do là khi ứng dụng được chạy lên thì các model (form, input, ...) trong Controller hiện tại sẽ được khởi tạo và lưu vào object $scope với key tương ứng name của nó. Nếu input nằm trong Form thì ta có thể dùng cú pháp trên để gọi tới nó.

3. Các tham số của ng-model-options trong AngularJS

Các thông số options dưới đây sẽ được gắn vào Model hiện tại:

  • updateOn: Quyết định khi nào thì thao tác update dữ liệu vào trong $scope, thường là blur, default, kepress ....
  • debounce: Giá trị của nó kiểu INT và nó quyết định sau khoảng bao lâu thì thao tác update dữ liệu vào $scope được thực hiện
  • getterSetter: Chúng ta sẽ tìm hiểu thông qua phần 4 nhé, đơn giản nó là những phương thức get, set giống trong C++, C# hay PHP.
  • Còn hai options nữa là allowInvalid, timezone nhưng chúng ta sẽ tìm hiểu nó sau nhé.

4. Các ví dụ về ng-model-options trong AngularJS

Sau đây chúng ta sẽ tìm hiểu một vài ví dụ liên quan đến Directive ng-model-options nhé, hãy chắc chắn rằng bạn đã đọc qua lý thuyết ở trên kia trước khi vào các ví dụ này.

Cách sử dụng ng-model-options (updateOn)

updateOn dùng để thiết lập khi nào thì thay đổi giá trị cho model

Trong ví dụ này ta sẽ thực hiện một chương trình như sau, chúng ta sẽ có một thẻ input và một thẻ span dùng để hiển thị giá trị của nó lúc nhập liệu. Chúng ta sẽ chia ra làm 2 bài, 1 bài có sử dụng options updateOn và một bài không có sử dụng.

Bài 1: Không sử dụng ng-model-options updateOn

XEM DEMO

<!doctype html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Ví dụ sử dụng Directive</title>
        <style>*{margin:0}body{padding:20px}</style>
        <script src="//ajax.googleapis.com/ajax/libs/angularjs/1.3.2/angular.min.js"></script>
        <script language="javascript">
            angular.module('myapp', [])
                    .controller('optionsController', ['$scope', function($scope) {
                        
                    }]);
        </script>
    </head>
    <body ng-app="myapp">
        <div ng-controller="optionsController">
            <form name="userForm">
                <h5>Nhập nội dung của bạn nào</h5>
                <input type="text" name="userName" ng-model="user.name"/><br />
                <h5>Chuỗi mà Bạn đang nhập là:</h5>
                <span ng-bind="user.name"></span>
            </form>
        </div>
    </body>
</html>
Giao diện:

demo ng-model-options trong angularjs

Khi bạn nhập dữ liệu thì bên dưới sẽ thay đổi theo bởi vì mình sử dụng cơ chế liên kết data binding (ng-bind).

Bài 2: Có sử dụng ng-model-options updateOn

XEM DEMO

<!doctype html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Ví dụ sử dụng Directive</title>
        <style>*{margin:0}body{padding:20px}</style>
        <script src="//ajax.googleapis.com/ajax/libs/angularjs/1.3.2/angular.min.js"></script>
        <script language="javascript">
            angular.module('myapp', [])
                    .controller('optionsController', ['$scope', function($scope) {
                        
                    }]);
        </script>
    </head>
    <body ng-app="myapp">
        <div ng-controller="optionsController">
            <form name="userForm">
                <h5>Nhập nội dung của bạn nào</h5>
                <input type="text" name="userName" ng-model-options="{updateOn:'blur'}" ng-model="user.name"/><br />
                <h5>Chuỗi mà Bạn đang nhập là:</h5>
                <span ng-bind="user.name"></span>
            </form>
        </div>
    </body>
</html>
Giao diện:

Các bạn thấy ở ví dụ này mình có thêm thuộc tính ng-model-options="{updateOn:'blur'}" có nghĩa rằng khi ta nhập dữ liệu và con trỏ chuột thoát khỏi ô input đó thì sự kiện update lưu vào trong $scope mới thực hiện chính vì vậy nó không thay đổi khi ta đang nhập.

Cách sử dụng ng-model-options (debounce)

debounce dùng để khai báo một khoảng thời gian nào đó thì sự kiện update giá trị vào $sope mới thực hiện.

Ví dụ: Trong ví dụ này ta sẽ xây dựng một ứng dụng tương tự như hai ví dụ trên, chỉ khác ở chỗ khi ta ngưng gõ khoảng thời gian  1 giây thì sự kiện update giá trị vào $scope mới thực hiện.

XEM DEMO

<!doctype html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Ví dụ sử dụng Directive</title>
        <style>*{margin:0}body{padding:20px}</style>
        <script src="//ajax.googleapis.com/ajax/libs/angularjs/1.3.2/angular.min.js"></script>
        <script language="javascript">
            angular.module('myapp', [])
                    .controller('optionsController', ['$scope', function($scope) {
                        
                    }]);
        </script>
    </head>
    <body ng-app="myapp">
        <div ng-controller="optionsController">
            <form name="userForm">
                <h5>Nhập nội dung của bạn nào</h5>
                <input type="text" name="userName" ng-model-options="{debounce:1000}" ng-model="user.name"/><br />
                <h5>Chuỗi mà Bạn đang nhập là:</h5>
                <span ng-bind="user.name"></span>
            </form>
        </div>
    </body>
</html>
Chạy lên bạn gõ vào và ngưng gõ khoảng 1 giây thì dữ liệu sẽ được lưu vào $scope, nên ng-bind sẽ lấy trong $scope và in ra ngoài màn hinh ngay tại thẻ span (thẻ ta khai báo ng-bind).

Kết hợp debouce vaf updateOn

Chuyện gì sẽ xảy ra nếu ta kết hợp cả hai options này lại với nhau? Rất đơn giản nếu ta sử dụng nhiều options với nhau thì nó sẽ chạy từng options cho tới khi xong hết thì mới cập nhật $scope. Ví dụ dưới đây ta sẽ nhập vào và khi con trỏ chuột ra khỏi input thì khoảng 1 giây sau thì $scope được cập nhật, còn nếu ta không đưa con trỏ ra ngoài thì hành động cập nhật $scope này không được xử lý.

XEM DEMO

<!doctype html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Ví dụ sử dụng Directive</title>
        <style>*{margin:0}body{padding:20px}</style>
        <script src="//ajax.googleapis.com/ajax/libs/angularjs/1.3.2/angular.min.js"></script>
        <script language="javascript">
            angular.module('myapp', [])
                    .controller('optionsController', ['$scope', function($scope) {
                        
                    }]);
        </script>
    </head>
    <body ng-app="myapp">
        <div ng-controller="optionsController">
            <form name="userForm">
                <h5>Nhập nội dung của bạn nào</h5>
                <input type="text" name="userName" ng-model-options="{updateOn:'blur', debounce:1000}" ng-model="user.name"/><br />
                <h5>Chuỗi mà Bạn đang nhập là:</h5>
                <span ng-bind="user.name"></span>
            </form>
        </div>
    </body>
</html>

ng-model-options getterSetter

Bạn có từng nghe qua phương thức get, set trong C#, C++ hay thậm chí là PHP không nhỉ? Chắc là có rồi nên mình không nói nhiều nữa về vấn đề này nhé. Ví dụ dưới đây có sử dụng getterSetter, các bạn để ý kỹ nhé.

XEM DEMO

<!doctype html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Ví dụ sử dụng Directive</title>
        <style>*{margin:0}body{padding:20px}</style>
        <script src="//ajax.googleapis.com/ajax/libs/angularjs/1.3.2/angular.min.js"></script>
        <script language="javascript">
            angular.module('myapp', [])
            .controller('optionsController', ['$scope', function($scope) {
                var _name = 'Freetuts.net';
                $scope.user = {
                    name: function(newName) {
                            return angular.isDefined(newName) ? (_name = newName) : _name;
                        }
                    };
                }]);
        </script>
    </head>
    <body ng-app="myapp">
        <div ng-controller="optionsController">
            <form name="userForm">
                <h5>Nhập nội dung của bạn nào</h5>
                <input type="text" name="userName" ng-model-options="{ getterSetter: true }" ng-model="user.name"/><br />
                <h5>Chuỗi mà Bạn đang nhập là:</h5>
                <span ng-bind="user.name()"></span>
            </form>
        </div>
    </body>
</html>
Trong ví dụ này khi chạy lên lúc ta chưa nhập gì thì input có giá trị là freetuts.net, tại sao? Lý do chính là ta sử dụng thuộc tính getterSetter trong ng-model-options, giá trị của nó sẽ là true hoặc false, nếu true thì cho phép sử dụng getterSetter và ngược lại nếu false thì không có sử dụng getterSetter.

Các bạn để ý thêm đoạn mã JS dưới đây:

var _name = 'Freetuts.net';
$scope.user = {
    name: function(newName) {
        return angular.isDefined(newName) ? (_name = newName) : _name;
    }
};
trong đoạn này ta sử dụng hàm angular.isDefined để kiểm tra biến đó có được định nghĩa hay không, nếu có thì gán giá trị mới đó vào trong biến _name, còn không thì không gán gì và cuối cùng là trả _name về (biến _name được khởi tạo ban đầu bằng 'freetuts.net'). Như vậy ở đoạn mã html <span ng-bind="user.name()"></span> sẽ nhận được giá trị đó nên sẽ in ra ngoài trình duyệt.

5 Lời kết

Cũng hơi dài rồi nên mình sẽ ngưng bài viết tại đây, các bạn chú ý then chốt của bài này là hướng dẫn các bạn sử dụng Directive ngModelOptions để kết hợp với ngModel, mục đích cuối cùng là giúp bạn có cái nhìn tổng quát nên vẫn không thật sự đầy đủ cho lắm, các bạn lên mạng vào các trang nước ngoài và tìm hiểu thêm nhé. Bài tiếp theo chúng ta sẽ tìm hiểu về một Directive khác mà ta cũng từng sử dụng rồi, đó là ng-bind.

Khóa học Angular 1x kết hợp với PHP và MySQL rất hay

Nếu bạn đang tìm hiểu Angular 1x + PHP/MySQL thì hãy tham khảo khóa học tạo ứng dụng Angular này, đây là khóa học được biên soạn bởi anh Việt, giảng viên tại fedu.vn. Trong khóa học này bạn sẽ được hướng dẫn sử dụng Angular 1  để hiển thi dữ liệu được trả về từ Server (PHP và MySQL).

Nguồn: freetuts.net