Tạo và sử dụng directive trong AngularJS
Khám phá cách tạo và sử dụng directive trong AngularJS để tăng tính linh hoạt và hiệu quả cho ứng dụng web của bạn.
Tạo và sử dụng directive trong AngularJS không chỉ giúp tăng tính linh hoạt và hiệu quả cho ứng dụng của bạn, mà còn giúp giảm thiểu độ phức tạp trong quá trình phát triển. Với directive, bạn có thể tạo ra các thành phần như buttons, menus, sliders, modals, tooltips, và nhiều hơn nữa, và sử dụng chúng trong toàn bộ ứng dụng của bạn. Bắt đầu khám phá tất cả những gì directive có thể mang lại cho ứng dụng của bạn ngay hôm nay!
Directive trong AngularJS là gì?
Directive trong AngularJS là một tính năng cho phép bạn tạo ra các thành phần tùy chỉnh và mở rộng các thành phần HTML cơ bản để sử dụng trong ứng dụng của mình. Directive cho phép bạn thêm các hành vi và tính năng mới cho các thành phần HTML đã có sẵn, hoặc tạo ra các thành phần HTML mới hoàn toàn. Với Directive, bạn có thể tạo ra các thành phần như buttons, menus, sliders, modals, tooltips, và nhiều hơn nữa.
Các loại directive: element, attribute, class, comment
Trong AngularJS, có bốn loại directive: element, attribute, class và comment.
Bài viết này được đăng tại [free tuts .net]
-
Element Directive: Đây là loại directive mà được sử dụng dựa trên thẻ HTML. Nếu một directive được sử dụng như một thẻ HTML, nó được gọi là Element Directive. Ví dụ:
<my-directive></my-directive>.
-
Attribute Directive: Đây là loại directive mà được sử dụng bằng cách thêm thuộc tính cho một thẻ HTML. Nếu một directive được sử dụng như một thuộc tính của thẻ HTML, nó được gọi là Attribute Directive. Ví dụ:
<div my-directive></div>
. -
Class Directive: Đây là loại directive mà được sử dụng bằng cách thêm một lớp cho một thẻ HTML. Nếu một directive được sử dụng như một lớp của thẻ HTML, nó được gọi là Class Directive. Ví dụ:
<div class="my-directive"></div>.
-
Comment Directive: Đây là loại directive mà được sử dụng bằng cách thêm một chú thích cho một phần tử HTML. Nếu một directive được sử dụng như một chú thích của phần tử HTML, nó được gọi là Comment Directive. Ví dụ:
<!-- directive: my-directive -->.
Mỗi loại directive có một cách sử dụng và một mục đích riêng trong AngularJS, tùy thuộc vào các yêu cầu của ứng dụng của bạn.
Các bước tạo directive trong AngularJS
Khai báo directive: restrict, template, scope
Khai báo Directive trong AngularJS thường bao gồm ba thuộc tính chính: restrict, template và scope.
Restrict: Thuộc tính restrict được sử dụng để chỉ định loại directive, được định nghĩa bằng một chuỗi gồm các ký tự E, A, C hoặc M:
- E (Element): được sử dụng như một thẻ HTML. Ví dụ:
<my-directive></my-directive>.
- A (Attribute): được sử dụng như một thuộc tính của thẻ HTML. Ví dụ:
<div my-directive></div>.
- C (Class): được sử dụng như một lớp của thẻ HTML. Ví dụ:
<div class="my-directive"></div>.
- M (Comment): được sử dụng như một chú thích của phần tử HTML. Ví dụ:
<!-- directive: my-directive -->.
Bạn có thể kết hợp các ký tự để chỉ định nhiều loại directive, ví dụ EA (Element và Attribute).
Template: Thuộc tính template xác định nội dung của directive bằng một chuỗi HTML hoặc một đường dẫn tới một file HTML. Nội dung này sẽ được thêm vào vào vị trí mà directive được sử dụng trong ứng dụng.
Scope: Thuộc tính scope được sử dụng để chỉ định phạm vi (scope) của directive. Nếu thuộc tính scope được định nghĩa, directive sẽ được đóng gói trong một phạm vi riêng biệt khỏi các phạm vi khác trong ứng dụng. Điều này giúp tăng tính độc lập và linh hoạt của directive.
Ví dụ:
var app = angular.module("myapp", []); angular.module('myApp').directive('myDirective', function() { return { restrict: 'E', template: '<div>Học lập trình miễn phí tại Freetuts.net, {{name}}!</div>', scope: { name: '@' } }; });
Trong ví dụ trên, directive sẽ được sử dụng như một thẻ HTML (<my-directive></my-directive>)
với nội dung là chuỗi HTML '<div>Hello, {{name}}!</div>'.
Directive có một phạm vi riêng biệt với một thuộc tính name được truyền vào từ ngoài với cú pháp name: '@'.
Kết quả
Các thuộc tính của directive: link, compile
Trong AngularJS, Directive có hai thuộc tính quan trọng là link
và compile
, được sử dụng để xử lý, thay đổi hoặc tương tác với các thành phần trong phần tử DOM.
Link: Thuộc tính link được sử dụng để kết nối directive với phần tử DOM. Nó cung cấp cho directive một tập hợp các thông tin về phần tử và phạm vi (scope) của nó, cho phép directive tương tác và thay đổi các thành phần trong phần tử DOM.
Link function nhận vào hai tham số là scope và element. Trong đó, scope là phạm vi của directive, còn element là phần tử DOM mà directive được áp dụng lên.
Ví dụ:
var app = angular.module("myapp", []); angular.module('myApp').directive('myDirective', function() { return { restrict: 'E', template: '<div>Hello, {{name}}!</div>', scope: { name: '@' }, link: function(scope, element, attrs) { element.on('click', function() { alert('Clicked!'); }); } }; });
Trong ví dụ trên, khi người dùng nhấn vào phần tử chứa directive myDirective
, directive sẽ hiển thị một thông báo cảnh báo bằng cách sử dụng phương thức alert()
.
Compile: Thuộc tính compile được sử dụng để biên dịch directive trước khi nó được liên kết (link) với phần tử DOM. Thuộc tính này cho phép directive thay đổi cấu trúc của phần tử DOM hoặc thêm các thành phần khác vào phần tử đó.
Compile function nhận vào một tham số là element, đại diện cho phần tử DOM mà directive được áp dụng lên. Nó trả về một hàm link function, cho phép directive tương tác với phần tử và phạm vi của nó.
Ví dụ:
angular.module('myApp').directive('myDirective', function() { return { restrict: 'E', template: '<div>Hello, {{name}}!</div>', scope: { name: '@' }, compile: function(element, attrs) { element.addClass('highlight'); return function(scope, element, attrs) { element.on('click', function() { alert('Clicked!'); }); }; } }; });
Trong ví dụ trên, directive myDirective
sẽ thêm một lớp CSS với tên là highlight
vào phần tử được áp dụng lên. Ngoài ra, khi người dùng nhấn vào phần tử đó, directive
sẽ hiển thị một thông báo cảnh báo bằng cách sử dụng phương thức alert()
.
Các phương thức trong directive: controller, link
Trong AngularJS, directive có hai phương thức quan trọng là controller và link, được sử dụng để xử lý, thay đổi hoặc tương tác với các thành phần trong phần tử DOM.
Controller: Phương thức controller được sử dụng để xử lý logic của directive, giúp directive có thể tương tác với các thành phần trong phần tử DOM. Nó cung cấp một đối tượng phạm vi (scope) cho directive và cho phép directive tương tác với các thành phần của phần tử DOM.
Controller function nhận vào một tham số là $scope, đại diện cho phạm vi của directive. Trong function này, bạn có thể định nghĩa các hành động và phương thức để thực hiện logic của directive.
Ví dụ:
angular.module('myApp').directive('myDirective', function() { return { restrict: 'E', template: '<div>Hello, {{name}}!</div>', scope: { name: '@' }, controller: function($scope, $element, $attrs) { $scope.changeName = function(newName) { $scope.name = newName; }; } }; });
Trong ví dụ trên, directive myDirective có một phương thức controller được định nghĩa. Phương thức này có thể được sử dụng để thay đổi tên được hiển thị bằng cách gọi phương thức changeName().
Link: Phương thức link được sử dụng để kết nối directive
với phần tử DOM và xử lý các sự kiện hoặc thay đổi các thành phần của phần tử DOM. Nó cung cấp cho directive một tập hợp các thông tin về phần tử và phạm vi (scope) của nó, cho phép directive
tương tác và thay đổi các thành phần trong phần tử DOM.
Link function nhận vào hai tham số là $scope
và $element.
Trong đó, $scope là phạm vi của directive, còn $element
là phần tử DOM mà directive được áp dụng lên.
Ví dụ
angular.module('myApp').directive('myDirective', function() { return { restrict: 'E', template: '<div>Hello, {{name}}!</div>', scope: { name: '@' }, link: function($scope, $element, $attrs) { $element.on('click', function() { $scope.$apply(function() { $scope.name = 'World'; }); }); } }; });
Trong ví dụ trên, khi người dùng nhấn vào phần tử chứa directive myDirective, directive sẽ thay đổi tên được hiển thị thành "World" bằng cách sử dụng phương thức $apply().
Các ứng dụng của directive trong AngularJS
Tạo các thành phần UI tùy chỉnh
Trong AngularJS, việc tạo các thành phần UI tùy chỉnh có thể được thực hiện bằng cách sử dụng directive. Các directive cho phép bạn định nghĩa các thành phần UI độc đáo và tùy chỉnh để đáp ứng các yêu cầu đặc biệt của ứng dụng.
Ví dụ, nếu bạn muốn tạo một thành phần UI tùy chỉnh để hiển thị danh sách các sản phẩm, bạn có thể sử dụng directive như sau:
angular.module('myApp').directive('productList', function() { return { restrict: 'E', scope: { products: '=', onSelect: '&' }, template: '<ul>' + '<li ng-repeat="product in products" ng-click="onSelect({product: product})">{{product.name}}</li>' + '</ul>' }; });
Trong ví dụ trên, chúng ta đã tạo một directive tùy chỉnh có tên là productList
. Directive này có các thuộc tính như sau:
- restrict: chỉ định cách sử dụng directive, trong trường hợp này là E (element) để sử dụng như một phần tử.
- scope: chỉ định các thuộc tính sẽ được sử dụng trong directive và cách chúng sẽ được liên kết với các thuộc tính trong phần tử HTML. Directive productList có hai thuộc tính,
products
vàonSelect,
được liên kết với các thuộc tính có cùng tên trong phần tử HTML bằng cách sử dụng các biểu thức. - template: chỉ định nội dung của directive. Trong ví dụ này, nội dung của directive là một danh sách các sản phẩm được liệt kê dựa trên thuộc tính products, và mỗi sản phẩm sẽ được chọn bằng cách gọi phương thức
onSelect().
Khi directive được sử dụng trong phần tử HTML, bạn có thể truyền các giá trị cho các thuộc tính của directive bằng cách sử dụng các biểu thức. Ví dụ:
<product-list products="productList" on-select="onSelectProduct(product)"></product-list>
Trong ví dụ trên, chúng ta sử dụng directive productList
và truyền vào các giá trị cho thuộc tính products
và onSelect
. Khi người dùng chọn một sản phẩm trong danh sách, phương thức onSelectProduct
() sẽ được gọi và truyền vào đối tượng sản phẩm đã chọn.
Sử dụng directive để thực hiện validation trên các trường nhập liệu
Trong AngularJS, directive có thể được sử dụng để thực hiện validation trên các trường nhập liệu. Khi người dùng nhập liệu vào các trường, directive sẽ kiểm tra và trả về kết quả validation tương ứng.
Ví dụ, để kiểm tra xem một trường nhập liệu có chứa một số hay không, chúng ta có thể sử dụng directive như sau:
angular.module('myApp').directive('isNumber', function() { return { require: 'ngModel', link: function(scope, element, attrs, ctrl) { ctrl.$validators.isNumber = function(modelValue, viewValue) { if (ctrl.$isEmpty(modelValue)) { return true; } if (/^\d+$/.test(viewValue)) { return true; } return false; }; } }; });
Trong ví dụ trên, chúng ta đã tạo một directive có tên là isNumber
. Directive này có các thuộc tính như sau:
- require: chỉ định rằng directive này sẽ được sử dụng bởi một trường nhập liệu (ngModel).
- link: cung cấp một hàm để xử lý các sự kiện liên quan đến trường nhập liệu. Trong trường hợp này, chúng ta đã định nghĩa một hàm validator có tên là
isNumber
, để kiểm tra xem giá trị nhập liệu có phải là một số hay không.
Để sử dụng directive này trên một trường nhập liệu, chúng ta chỉ cần thêm thuộc tính is-number vào phần tử HTML tương ứng:
<input type="text" ng-model="myValue" is-number>
Khi người dùng nhập liệu vào trường này, directive isNumber sẽ được gọi để kiểm tra giá trị nhập liệu. Nếu giá trị nhập liệu không phải là một số, directive sẽ trả về kết quả validation không hợp lệ, và AngularJS sẽ hiển thị thông báo lỗi tương ứng.
Tương tự, chúng ta có thể sử dụng directive để kiểm tra các điều kiện khác trên các trường nhập liệu, ví dụ như độ dài, định dạng email, hoặc các điều kiện tùy chỉnh khác. Directive cung cấp cho chúng ta một cách tiện lợi để kiểm tra và xử lý dữ liệu nhập liệu từ người dùng.
Tối ưu hóa ứng dụng với directive
AngularJS cung cấp cho chúng ta directive để tạo các thành phần UI tùy chỉnh và đáp ứng các yêu cầu đặc biệt của ứng dụng. Tuy nhiên, nếu không sử dụng đúng cách, directive có thể dẫn đến tốc độ tải trang chậm và tốn tài nguyên.
Để tối ưu hóa ứng dụng với directive, chúng ta có thể áp dụng các kỹ thuật sau:
Sử dụng ng-if thay vì ng-show hoặc ng-hide trong directive có tính năng toggle visibility.
Khi sử dụng ng-show hoặc ng-hide, các phần tử bị ẩn vẫn được tải xuống trang, tuy nhiên nó không hiển thị trên giao diện. Khi sử dụng ng-if, phần tử sẽ chỉ được tải xuống và hiển thị trên giao diện khi điều kiện đúng.
Sử dụng transclude để tăng tính tái sử dụng của directive.
Transclude cho phép chúng ta đưa nội dung bên trong directive vào trong phần tử DOM của directive. Điều này giúp cho directive có thể được sử dụng lại trong nhiều vị trí khác nhau trên giao diện.
Không sử dụng templateUrl để tải template của directive trong quá trình runtime.
Sử dụng templateUrl để tải template của directive sẽ tăng thời gian tải trang. Thay vào đó, chúng ta nên sử dụng template để đặt template trực tiếp vào trong directive.
Sử dụng $watch và $observe với cẩn thận để tránh tạo ra các liên kết xem ngược.
Khi sử dụng $watch và $observe, chúng ta cần đảm bảo rằng chúng ta chỉ đăng ký các hàm xử lý thay đổi khi cần thiết. Việc đăng ký quá nhiều hàm xử lý thay đổi có thể dẫn đến các liên kết xem ngược, gây ra các lỗi và tốn tài nguyên.
Không sử dụng replace vì nó đã bị loại bỏ trong phiên bản AngularJS mới.
Directive với thuộc tính replace đã bị loại bỏ trong phiên bản AngularJS mới, nên không nên sử dụng nó. Thay vào đó, chúng ta nên sử dụng directive với template và transclude để tạo các thành phần UI tùy chỉnh.
Các ví dụ về tạo directive trong AngularJS
Tạo directive cho việc hiển thị thông báo
Để tạo directive cho việc hiển thị thông báo trong AngularJS, chúng ta có thể làm như sau:
Tạo file directive với tên là notification.js
và định nghĩa directive có tên là notification
như sau:
app.directive('notification', function() { return { restrict: 'E', replace: true, scope: { message: '=', type: '=' }, template: '<div class="alert alert-{{type}}">{{message}}</div>' }; });
Trong file HTML của ứng dụng, sử dụng directive notification
để hiển thị thông báo. Chúng ta có thể truyền vào message
và type
cho directive
thông qua thuộc tính:
<notification message="Hello world!" type="success"></notification>
Trong đó, message
là nội dung thông báo, type
là loại thông báo (ví dụ: success, error, warning, info).
Khi chạy ứng dụng, directive notification
sẽ hiển thị thông báo theo nội dung và loại được truyền vào.
Lưu ý: Để directive notification
hoạt động, chúng ta cần đảm bảo rằng đường dẫn đến file notification.js
được đăng ký trong file HTML và module của ứng dụng đã được khai báo để sử dụng directive.
Tạo directive cho việc thực hiện xác thực mật khẩu
Để tạo directive cho việc thực hiện xác thực mật khẩu trong AngularJS, chúng ta có thể làm như sau:
Tạo file directive với tên là password-match.js
và định nghĩa directive có tên là passwordMatch
như sau:
app.directive('passwordMatch', function() { return { restrict: 'A', require: 'ngModel', link: function(scope, element, attrs, ngModel) { ngModel.$validators.passwordMatch = function(modelValue) { return modelValue === scope.$eval(attrs.passwordMatch); }; scope.$watch(attrs.passwordMatch, function() { ngModel.$validate(); }); } }; });
Trong đó, chúng ta sử dụng $validators
của ngModel để kiểm tra xem giá trị nhập vào có trùng khớp với giá trị của trường nhập khẩu khác hay không. Sau đó, sử dụng $watch
để kiểm tra sự thay đổi trong trường nhập khẩu khác và xác thực lại giá trị của trường nhập khẩu hiện tại.
Trong file HTML của ứng dụng, sử dụng directive passwordMatch
để xác thực mật khẩu. Chúng ta có thể truyền vào tên của trường nhập khẩu khác thông qua thuộc tính:
<input type="password" ng-model="password" name="password"> <input type="password" ng-model="confirmPassword" name="confirmPassword" password-match="password">
Trong đó, password
là tên của trường nhập khẩu được xác thực và confirmPassword
là tên của trường nhập khẩu khác được sử dụng để kiểm tra xác thực.
Khi chạy ứng dụng, directive passwordMatch
sẽ kiểm tra xác thực mật khẩu và thông báo lỗi nếu giá trị nhập vào không trùng khớp với giá trị của trường nhập khẩu khác.
Kết quả
Lưu ý: Để directive passwordMatch
hoạt động, chúng ta cần đảm bảo rằng đường dẫn đến file password-match.js
được đăng ký trong file HTML và module của ứng dụng đã được khai báo để sử dụng directive.
Tạo directive cho việc hiển thị ảnh
Để tạo directive cho việc hiển thị ảnh trong AngularJS, chúng ta có thể làm như sau:
Tạo file directive với tên là image-src.js
và định nghĩa directive có tên là imageSrc
như sau:
app.directive('imageSrc', function() { return { restrict: 'A', link: function(scope, element, attrs) { var img = new Image(); img.onload = function() { element.attr('src', attrs.imageSrc); }; img.onerror = function() { element.attr('src', 'default-image.jpg'); }; img.src = attrs.imageSrc; } }; });
Trong đó, chúng ta sử dụng thuộc tính onload của đối tượng Image để kiểm tra xem ảnh đã được tải thành công hay chưa. Nếu ảnh đã được tải thành công, chúng ta sẽ cập nhật đường dẫn của ảnh vào thuộc tính src của thẻ <img>
. Nếu ảnh không tải được, chúng ta sẽ sử dụng một hình ảnh mặc định.
Trong file HTML của ứng dụng, sử dụng directive imageSrc
để hiển thị ảnh. Chúng ta có thể truyền vào đường dẫn của ảnh thông qua thuộc tính:
<img image-src="{{ imageUrl }}">
Trong đó, imageUrl
là đường dẫn của ảnh được truyền vào.
Khi chạy ứng dụng, directive imageSrc
sẽ tải ảnh và hiển thị lên trang web của bạn.
Lưu ý: Để directive imageSrc hoạt động, chúng ta cần đảm bảo rằng đường dẫn đến file image-src.js
được đăng ký trong file HTML và module của ứng dụng đã được khai báo để sử dụng directive.
Kết quả
Ngoài ra, chúng ta cũng cần đảm bảo rằng ảnh được truyền vào đúng định dạng và đường dẫn là chính xác.
Kết bài viết
Như vậy, chúng ta đã tìm hiểu về directive trong AngularJS và cách sử dụng chúng để tạo các thành phần UI tùy chỉnh, đáp ứng các yêu cầu đặc biệt của ứng dụng. Chúng ta đã đi sâu vào các khái niệm cơ bản của directive như các loại, các thuộc tính và phương thức, cũng như tạo ra một số ví dụ cụ thể để minh họa cách sử dụng chúng.
Điều quan trọng cần nhớ là khi sử dụng directive trong AngularJS, chúng ta có thể tùy biến các thành phần UI để phù hợp với các yêu cầu đặc biệt của ứng dụng. Tuy nhiên, việc sử dụng quá nhiều directive có thể làm giảm hiệu suất của ứng dụng, do đó chúng ta cần tối ưu hóa chúng để đảm bảo tốc độ tải trang nhanh chóng và mượt mà.
Tổng kết lại, việc sử dụng directive là một trong những cách quan trọng để tạo các thành phần UI tùy chỉnh trong AngularJS. Hi vọng bài viết này sẽ giúp bạn hiểu rõ hơn về cách sử dụng directive và tận dụng chúng để tạo ra các ứng dụng chất lượng cao.