+3

[AngularJS toàn tập] Phần 11 : ng-model-options trong AngularJS

[AngularJS toàn tập] Phần 11 : ng-model-options trong AngularJS

Ở các phần trước mình đã hướng dẫn các bạn về một directive quan trọng đó là ng-model, và cũng có một vài ví dụ cho bạn về chủ đề này. Để tiếp tiếp tục AngularJS toàn tập thì trong bài này chúng ta sẽ tìm hiểu 1 directive rất quan trọng và liên quan đến ng-model đó chính là ng-model-options trong AngularJS. Note : như các bạn thấy trong các phần trước mình luôn viết từng phần kèm theo các ví dụ, rất mong các bạn xem kĩ các phần ví dụ đó vì nó giúp cho các bạn dễ hiểu hơn rất nhiều. Và nếu có thời gian thì bạn có thể làm lại ví dụ đó.

ng-model-options là gì?

Đúng như cái tên của nó là ng-mode-options thì chúng ta sẽ dùng ng-model-option để setting một số thông số liên quan đến ng-model. Lúc mà ứng dụng được khởi chạy thì Directive này sẽ thực hiện trước sau đó ng-model mới được tạo.

Những thông số được 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 lưu thì lúc nào sẽ lưu? Và nó sẽ được lưu bằng cách nào? Tất cả những điều đó chính là ng-model-options trong angular.

Tìm hiểu $rollbackViewValue

Thông thường mỗi khi thay đổi dữ liệu thì bạn thấy rằng dữ liệu đó sẽ được lưu vào $scope nên những thuộc tính nào được liên kết (ng-bind) với nó cũng sẽ được thay đổi. Nhưng có những trường hợp bạn muốn người dùng nhập vào nhưng không thay đổi trong $scope thì sao? Và bạn cần lấy những giá trị nguyên thủy này thì sao?

Rất đơn giản là bạn sử dụng $roolbackViewValue để giải quyết vấn đề này, bởi vì $roolbackViewValue 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;

Vì sao lại phải thông qua $scope? Bởi vì 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ó.

Tham số của ng-model-options trong AngularJS

Đây là các options mà bạn có thể sử dụng:

  • 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: Đơn giản nó là những phương thức get, set giống trong C++, C# hay PHP.
  • allowInvalid, timezone : chúng ta sẽ tìm hiểu nó sau.

Ví dụ về ng-model-options trong AngularJS

Và bây giờ chúng ta sẽ tìm hiểu một vài ví dụ liên quan đến Directive ng-model-options, 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: Quyết định khi nào thì thao tác update dữ liệu vào trong $scope, thường là blur, default, kepress ....

Ở 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 demo, 1 demo có sử dụng options updateOn và một demo không có sử dụng - để xem chúng khác nhau như thế nào.

Không sử dụng ng-model-options updateOn

<html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Ví dụ</title>
        <style>*{margin:0}body{padding:20px}</style>
        <script src="//ajax.googleapis.com/ajax/libs/angularjs/1.4.8/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 tên của bạn</h5>
                <input type="text" name="userName" ng-model="user.name"/><br />
                <h5>Bạn đang nhập là:</h5>
                <span ng-bind="user.name"></span>
            </form>
        </div>
    </body>
</html>

Link demo : https://jsfiddle.net/SonCheDinh/jhdzLe9x/

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).

Có sử dụng ng-model-options updateOn

<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 tên của bạn</h5>
                <input type="text" name="userName" ng-model-options="{updateOn:'blur'}" ng-model="user.name"/><br />
                <h5>Bạn đang nhập là:</h5>
                <span ng-bind="user.name"></span>
            </form>
        </div>
    </body>
</html>

Xem demo tại : https://jsfiddle.net/SonCheDinh/hmatv0sk/

Ở 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: 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

Ở 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.

<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 tên của bạn</h5>
                <input type="text" name="userName" ng-model-options="{debounce:1000}" ng-model="user.name"/><br />
                <h5>Bạn đang nhập là:</h5>
                <span ng-bind="user.name"></span>
            </form>
        </div>
    </body>
</html>

Xem demo tại : https://jsfiddle.net/SonCheDinh/w4zu6L4u/

Như các bạn thấy khi bạn gõ vào và ngưng gõ khoảng 1 giây (mình set giá trị là debounce:1000) 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).

Sử dụng debouce cùng với updateOn

Điều 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ý.

<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 tên của bạn:</h5>
                <input type="text" name="userName" ng-model-options="{updateOn:'blur', debounce:1000}" ng-model="user.name"/><br />
                <h5>Bạn đang nhập là:</h5>
                <span ng-bind="user.name"></span>
            </form>
        </div>
    </body>
</html>

Xem demo tại : https://jsfiddle.net/SonCheDinh/8h8ccdyc/

ng-model-options getterSetter

Chắc hẳn bạn đã biết đến phương thức get, set trong C#, C++,PHP rồi. Ví dụ dưới đây có sử dụng getterSetter, các bạn để ý kỹ nhé.

<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 = 'Viblo.asia';
                $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 tên của bạn:</h5>
                <input type="text" name="userName" ng-model-options="{ getterSetter: true }" ng-model="user.name"/><br />
                <h5>Bạn đang nhập là:</h5>
                <span ng-bind="user.name()"></span>
            </form>
        </div>
    </body>
</html>

Xem demo tại : https://jsfiddle.net/SonCheDinh/ekkxpyuq/

Khi chạy lên lúc ta chưa nhập gì thì input có giá trị là Viblo.asia, 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.

function($scope) {
  var _name = 'Viblo.asia';
  $scope.user = {
    name: function(newName) {
      return angular.isDefined(newName) ? (_name = newName) : _name;
    }
  };
}

Ở đ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 'Viblo.asia'). 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.

Ok, phần hướng dẫn ngày hôm nay đến đây là kết thúc, hẹn các bạn ở các phần sau.


All rights reserved

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí