Series AngularJS cho người mới: Custom Directives

Chào mừng các bạn đến với bài tiếp theo trong series AngularJS cho người mới. Trong bài ngày hôm nay chúng ta sẽ học cách tạo ra một vài directive để cho source code của chúng ta rõ ràng, trong sáng, dễ quản lý hơn.

Để làm cho source code của chúng ta trong sáng, rõ ràng và dễ quản lý hơn thì một trong những cách đó là reuse code. Điều này không có nghĩa là cứ copy và paste là xong. Cụ thể nhìn vào code block dưới đây.

<h1>
{{product.name}}
<em class="pull-right">{{product.price | currency}}</em>
</h1>
view raw reuse.html hosted with ❤ by GitHub

Rõ ràng đoạn code này có thể được sử dụng lại ở rất nhiều chỗ, vậy làm thế nào để hạn chế việc trùng lặp trong toàn bộ source code.

Angular cung cấp cho chúng ta một số cách. Cách đầu tiên là sử dụng ng-include để sử dụng template. Cách sử dụng vô cùng đơn giản, chúng ta move code block cần include ra 1 file khác, giả sử tôi đặt tên là product-title.html, sau đó sử dụ ng-include đối với file vừa tạo. Cụ thể.

// product-title.html
{{product.name}}
<em class="pull-right">{{product.price | currency}}</em>
// usage
<h1 ng-include="'product-title.html'"></h1>
view raw gistfile1.txt hosted with ❤ by GitHub

Lưu ý, giá trị truyền vào ng-include sẽ là một chuỗi, mô tả đường dẫn tới file template, vì thế đừng quên cặp đấu nháy đơn nhé.

Cách ng-include hoạt động được mô tả như thế này.

Selection_052.png

Bất cứ khi nào browser đọc đến ng-include, nó sẽ báo cho angular biết để load về cái file template tương ứng.

Như vậy các bạn đã biết cách sử dụng template thông qua ng-include là cách đầu tiên, vậy cách thứ hai là gì?

Angular cung cấp cho các bạn phương thức để tạo custom directive. Đây chính là cách thứ hai. Với custom directive, các bạn có thể code như sau.

// ng-include
<h3 ng-include="'product-title.html'"></h3>
// custom directive
<product-title></product-title>
view raw custom.html hosted with ❤ by GitHub

Và đây cũng cách cách tôi khuyên các bạn nên làm theo. Tại sao?

Các directive gíup cho các bạn viết page HTML một cách dễ dàng, đơn giản hơn, đồng thời cũng giúp diễn tả được hành vi của application trong HTML page. Chẳng hạn như sau.

<aside class="col-sm-3">
<song-cover></song-cover>
<h4><song-rating></song-rating></h4>
</aside>
<div class="col-sm-9">
<h3><song-title></song-title></h3>
<song-short-description></song-short-description>
<song-genres></song-genres>
</div>
view raw song.html hosted with ❤ by GitHub

Thấy rất dễ hiểu các thành phần được hiển thại đúng không nào. Tóm lại sử dụng custom directive để.

  • Mô tả những giao diện phức tạp, nhiều thành phần.
  • Dễ dàng gọi event, cũng như đăng kí các event handler cho mỗi thành phần.
  • Dễ dàng sử dụng lại các common component.

 Vậy thì làm sao để viết một custom directive. Đơn giản thôi, tôi sẽ hướng dẫn các bạn ngay sau đây.

Ví dụ để khai báo directive product-title ta dùng đoạn code dưới đây.

app.directive('productTitle', function(){
return {
// configuration describe how directive work
};
});

Các bạn lưu ý, Angular sử dụng camelCase để khai báo trong Javascript, vì thế khi khai báo các bạn chọn tên là productTitle trong Javascript thì directive thật sự trong HTML sẽ là product-title.

Về các config của một directive, ví dụ như sau.

app.directive('productTitle', function(){
return {
restrict: 'E',
templateUrl: 'product-title.html'
};
});

Về templateUrl chắc các bạn dễ hiểu, và best practice là luôn cố gắng break trang HTML của bạn ra nhiều template nhất có thể, để có thể dễ dàng tái sử dụng. Còn về restrict, là cách để trigger directive. Chẳng hạn như bằng class name (C), element name (E), attribute name (A) hoặc cả ba (ACE). Các bạn có thể tìm hiểu thêm tại https://docs.angularjs.org/guide/directive

// Element directive
<product-title></product-title>
// Attribute directive
<h3 product-title></h3>
view raw directive.html hosted with ❤ by GitHub

Một vài best practice cho việc sử dụng custom directive.

  • Đừng bao giờ sử dụng self-closing tag (<product />) bởi vì một số browser sẽ có thể không hỗ trợ, hãy luôn sử dụng dạng đầy đủ của tag.
  • Sử dụng custom element directive cho các UI widgets, sử dụng các custom attribute directive cho các mixin behaviors như tooltip, …

Ngoài ra, như thế nào để sử dụng custom directive với controller. Ví dụ chúng ta sẽ chuyển product panels ra một custom directive.

<section>
<ul class="nav nav-pills">
...
</ul>
<div class="panel" ng-show="panel.isSelected('description')">
...
</div>
<div class="panel" ng-show="panel.isSelected('specification')">
...
</div>
<div class="panel" ng-show="panel.isSelected('review')">
...
</div>
</section>

Chuyển controller vào trong directive.

app.directive('productPanels', function(){
return {
restrict: 'E',
templateUrl: 'product-panels.html',
controller: function () {
this.tab = 'description';
this.setTab = function (tab) {
this.tab = tab;
};
this.isSelected = function (tab) {
return this.tab === tab;
}
},
controllerAs: 'panel'
};
});

Chỉnh sửa file index.html.

<h1>
<product-title></product-title>
</h1>
<product-panels></product-panels>
view raw index.html hosted with ❤ by GitHub

Thật sự bây giờ code trong file index.html đã rõ ràng hơn rất nhiều phải không nào.

Qua bài viết này hy vọng các bạn đã hiểu cách sử dụng cũng như lợi ích khi sử dụng custom directive. Trong bài sau, cũng là bài cuối cùng của series, tôi sẽ giới thiệu với các bạn về Dependency và Service, cũng như các built-in services trong Angular.

Đừng quên source code trong bài sẽ được tìm thấy tại https://github.com/codeaholicguy/angular-tutorial

Tạm biệt, và hẹn gặp lại.

Một suy nghĩ 5 thoughts on “Series AngularJS cho người mới: Custom Directives

  1. mình có 1 đoạn jquery dùng để thay đổi kích thước của vài div và muốn viết thành 1 directive. Các bạn giúp mình với.

    var heightWithoutNavbar = $(“body #wrapper”).height() – 61;
    $(“.sidebard-panel”).css(“min-height”, heightWithoutNavbar + “px”);

    var navbarHeigh = $(‘nav.navbar-default’).height();
    var wrapperHeigh = $(‘#page-wrapper’).height();

    if (navbarHeigh > wrapperHeigh) {
    $(‘#page-wrapper’).css(“min-height”, navbarHeigh + “px”);
    }
    if (navbarHeigh wrapperHeigh) {
    $(‘#page-wrapper’).css(“min-height”, navbarHeigh – 60 + “px”);

    } else {
    $(‘#page-wrapper’).css(“min-height”, $(window).height() – 60 + “px”);
    }
    }

  2. Mình có tạo ra 1 directive là product Review . code như sau:
    app.directive(‘productReview’,function(){
    return {
    restrict: ‘E’,
    templateUrl: ‘product-review.html’,
    controller: function() {
    this.review = {};
    this.addReview = function(product) {
    product.reviews.push(this.review);
    }
    },
    controllerAs: ‘reviewCtrl’
    }
    })
    //File product-review.html. (nội dung giống phần code trong git hub).

    ….

    Nhưng mình thay this.addReview bằng với $scope.addReview thì nó sinh ra lỗi, nó không hiển thị các content của directive productReview nữa.
    Bạn giúp mình diễn giaỉ vấn đề $scope và this trong directive ở 1 bài viết khác được không.
    Cám ơn bạn vì series angularjs dành cho người mới này :D

    1. Rất cảm ơn sự quan tâm của bạn, thật sự rất xin lỗi vì sự trả lời chậm trễ này. Mình sẽ cố gắng viết một bài về $scope trong angular 1.x trong thời gian sớm nhất có thể. Về phần lỗi trong code của bạn đưa ra, bạn có thể liên chat trực tiếp với mình thông quan fanpage để mình có thể giúp bạn được nhiều hơn. Mong bạn sẽ tiếp tục quan tâm và ủng hội các bài viết của mình.

      Thân.

Bình luận

Điền thông tin vào ô dưới đây hoặc nhấn vào một biểu tượng để đăng nhập:

WordPress.com Logo

Bạn đang bình luận bằng tài khoản WordPress.com Đăng xuất /  Thay đổi )

Facebook photo

Bạn đang bình luận bằng tài khoản Facebook Đăng xuất /  Thay đổi )

Connecting to %s