Cách sử dụng đúng $scope trong AngularJS
Bài đăng này đã không được cập nhật trong 8 năm
1, Sử dụng $rootScope
$rootScope là một biến global và được dùng nhiều nơi. Tuy nhiên việc sử dụng $rootScope sẽ làm cho code của chúng ta khó khi bảo trì. Việc sử dụng các biên ở trong các file javaScript, directives, controllers và templates cũng gây khó khăn trong việc unit test hay tái cấu trúc lại code.
Như vây, $rootScope có vấn đề gì khi sử dụng? Vấn đề này thực ra là vấn đề chúng ta sử dụng $rootScope như thế nào.
Thông thường chúng ta thường dùng $rootScope như sau:
- Các biến trong templates được gán cho $rootScope thay thế cho sử dụng $scope
- các hàm được gán cho các $rootScope được dùng trong các logic thay vì sử dụng trong controllers.
- Thông tin chi tiết của người dùng trong phiên làm việc được lưu trữ trong $rootScope mà khi nó cần được điều khiên bởi directive.
- Các developer thường dùng $rootScope như là một cách để chia sẻ data giữa các directives, controllers, templates trong khi AngularJS đã có các methods điều khiển việc này.
- $rootScope được sử dụng để lưu trữ các thông tin chung của ứng dụng như ngôn ngữ, người dùng hiện tại.
Chúng ta điều biết $rootScope là scope đầu tiên được tạo khi ứng dụng bắt đầu, và nó cho phép chúng ta sửa khi phương thức angular.module('myApp',[]).run(..)
được thực thi.
Một số cách dùng $rootScope:
- Chỉ thêm thuộc tính cho $rootScope khi dữ liệu gắn là các dữ liệu tĩnh hoặc constance. Bất cứ một giá trị động thì chúng ta lên sử dụng một scope và gán cho một elemen trong DOM.
- Nếu chúng ta không thể khai báo một thuộc tính mới cho $rootScope khi ứng dụng bắt đầu thì khi đó thì không liên quan gì đên
$rootScope
- Tất cả sửa đổi
$rootScope
nên diễn ra ở một nơi, khi chúng ta cần tìm hiểu về các$rootScope
đã được khai báo hay đang sử dụng, chúng ta có thể dễ dàng tìm thấy trong một file javaScript.
Nơi hợp lý nhất là nơi chúng ta đặt phương thức angular.run()
(phương thức được thực thi khi AngulaJS khởi tạo ứng dụng ).
var app = angular.module('myApp',[]);
app.run(function($rootScope) {
$rootScope.Math = Math.
});
2. Sử dụng isolated scopes
Các scopes trong AngulaJS luôn luôn tự động kế thừa từ các scope cha, và trong việc phát triển các ứng dụng nó sẽ gây ra sự phức tạp khi có quá nhiều phân cấp.
Với đặc điểm như vậy, nó giúp cho các developer mới không phải lo lắng gì về mới liên kết phức tạp giưa các scope trong isolated scope nên sẽ dùng nó mặc định. Và nó chính là yếu tố mà các developer hay dùng khi sử dụng một scope đã tồn tại ở một cấp cao hơn trong template.
Một số nguyên nhân dẫn đến cách dùng trên là không tốt:
- Nó tạo ra một mối liên kết giữa hai template mà không được thực thi bởi angulaJS hay bất kì quy tắc nào.
- Khi sửa lỗi trong ứng dụng, nó sẽ gây ra những ảnh hưởng đến các chỗ khác mà chúng ta không thể nắm hết được.
- Có những nhược điểm như biến global.
Vì vậy chúng ta cần tránh việc sử dụng scope hiện tại và các thuộc tính vào các điểm con trong template. Thay thế vào đó là sử dụng chức năng transclude
và isolated scope.
Tuy nhiên có một vài kiểu directive không thể sử dụng isolated scope. Như các thuộc tính của directive được dùng trên các điểm HTML hay những loại directives được tạo lên với sự hiểu biết rằng $scope thuộc sở hữu của directive khác. Một directive được thiết kế tốt sẽ cung cấp một điều khiển để chúng ta có thể yêu cầu gọi các phương thức thay vì trực tiếp sửa đổi $scope.
3. Sử dụng data object cho các thuộc tính trong scope
Chúng ta có thể giảm thiểu việc tìm lỗi, sửa lỗi bằng một cách rất đơn giản, luôn luôn khai báo một data object
để lưu các giá trị trong các templates. Nó giúp giải quyết rất nhiều vấn đề hay gặp và giúp code dễ đọc hơn trong AngulaJS.
Ví dụ khi chúng ta không sử dụng data object
app.directive('product',function(){
return {
scope: {},
link: function($scope, $el) {
$scope.title = 'May Tinh';
$scope.amount = 100;
$scope.visible = true;
},
templateUrl: 'product.html'
});
<script type="text/ng-template" id="product.html">
<div ng-if="visible">
<h1>{{title}}</h1>
<input type="number" ng-model="amount"/>
</div>
</script>
Trong ví dụ trên, Template sẽ hiển thị thẻ <h1>{{title}}</h1>
đúng nhưng với việc chúng ta sử dụng thẻ input thì sẽ bị lỗi. Trong AngulaJS, khi chúng ta sư dụng directive có sử dụng việc truyền dữ liệu theo 2 chiều như ng-model
, nó sẽ không hoạt động trên biến đơn giản khi một scope con được tạo ra. Đó là những gì xảy ra khi ng-if = "visible" được thêm vào mẫu. Khi scope sử dụng một data object sẽ không bị lỗi khi các giá trị được thay đổi.
Khi scope được sử dụng data object
app.directive('product',function(){
return {
scope: {},
link: function($scope, $el) {
$scope.model = {
title: 'May Tinh',
amount: 100,
visible: = true;
};
},
templateUrl: 'product.html'
});
<script type="text/ng-template" id="product.html">
<div ng-if="model.visible">
<h1>{{model.title}}</h1>
<input type="number" ng-model="model.amount"/>
</div>
</script>
All rights reserved