5

Nói rằng tôi có này cấu trúc HTML như sau:

<body ng-app="demo" ng-controller="RootCtrl"> 
    <header> 
     <!-- Header Material --> 
    </header> 

    <main ng-controller="MainCtrl"> 
     <!-- Main Content --> 

     <nav ng-controller="NavCtrl"> 
      <!-- Navbar --> 
     </nav> 
    </main> 
<body> 

Bây giờ, giả sử NavCtrl nhu cầu để thao tác một mô hình điều đó xảy ra để tồn tại thuộc phạm vi RootCtrl 's - dưới những điều kiện nào sẽ $emit/$on thể phù hợp hơn? Và theo điều kiện nào thì tốt hơn là trực tiếp thao tác mô hình thông qua kế thừa phạm vi?

Trả lời

7

Nếu bạn đang sử dụng thừa kế nguyên mẫu, bạn cần phải cẩn thận vì rất dễ mắc lỗi khi sử dụng cùng tên biến trong bộ điều khiển cha và con. Điều này có thể tránh được bằng cách đảm bảo biến $ scope luôn luôn có dấu chấm ở một nơi nào đó, nhưng cần kỷ luật để đảm bảo bạn luôn làm điều này. Bạn cũng có thể truy cập một biến trong tập hợp NavCtrl trong RootCtrl bằng cách sử dụng cấu trúc $scope.$parent.$parent, nhưng điều này là giòn và về cơ bản gắn kết bộ điều khiển của bạn với cấu trúc DOM là công thức cho các sự cố xuống dòng.

$ emit/$ khi gặp sự cố về khả năng âm thầm không thành công nếu bạn đánh máy trong tên sự kiện và có thể khiến khó theo dõi những gì đang xảy ra trong trường hợp có lỗi. Tốt hơn là nên sử dụng chúng một cách tiết kiệm. http://eburley.github.io/2013/01/31/angularjs-watch-pub-sub-best-practices.html chỉ nói để sử dụng chúng "khi bạn cần cho phép nhiều người đăng ký biết về một sự kiện và những người đăng ký đó cần phải làm nhiều hơn là tỏa sáng thông tin cho chế độ xem của họ".

Cách góc thông thường để chia sẻ mô hình dữ liệu giữa các bộ điều khiển là tạo một dịch vụ và đưa vào cả hai bộ điều khiển thay thế. Điều này phù hợp với nguyên tắc "prefer composition over inheritance" của OOP nói chung.

app.service('dayService', function() {  
    var day = 'Monday'; 
    return { 
     getDay: function() { 
      return day; 
     }, 
     setDay: function(thisDay) { 
      day = thisDay; 
     } 
    }; 
}) 

function NavCtrl($scope, dayService) { 
    $scope.day = dayService.getDay(); 
} 

function RootCtrl($scope, dayService) { 
    dayService.setDay('Sunday'); 
} 

HTML:

<nav ng-controller="NavCtrl"> 
    Today is {{day}} 
</nav> 

Bạn cũng có thể tìm thấy Misko của video on Angular best practices thú vị, nó nói về những gì để đưa vào bộ điều khiển vs dịch vụ xung quanh mốc 28 phút, và nhiều hơn nữa về các sự kiện ($ phát ra/$ trên) về phía cuối. Kết luận của ông (diễn giải) là các sự kiện có phần khó hiểu nhất chỉ được sử dụng cho các tình huống mà hai điều thực sự không cần biết về nhau và phải được giữ riêng biệt, hoặc nếu sự kiện không phải lúc nào cũng cần thiết đôi khi có thể bỏ qua.

Tôi có thể nói nguyên tắc cơ bản là:

  • Sử dụng dịch vụ chia sẻ dữ liệu giữa hai bộ điều khiển, nó hơi phức tạp hơn thừa kế nhưng không có gì quá khó khăn.

  • Sử dụng sự kiện để chia sẻ giữa nhiều người đăng ký khác nhau theo những cách phức tạp.

  • Phạm vi $ trong bộ điều khiển phải là 'chỉ ghi' (quy tắc được lấy trực tiếp từ video thực hành tốt nhất của Misko ở trên). Phạm vi thừa kế nơi "NavCtrl cần thao tác một mô hình xảy ra tồn tại trong phạm vi của RootCtrl" sẽ liên quan đến việc đọc phạm vi cha mẹ quá, vì vậy tôi nghĩ là tốt nhất nên tránh.

1

Nếu mô hình trong RootCtrl là một đối tượng và NavCtrl chỉ cần sửa đổi vài thuộc tính của đối tượng mô hình, sử dụng kế thừa phạm vi sẽ là dễ nhất. Chỉ cần chắc chắn rằng bạn biết làm thế nào prototypal hoạt động nếu bạn muốn thực hiện phương pháp này.

Sử dụng dịch vụ chia sẻ dữ liệu giữa các trình điều khiển hoạt động, như đã đề cập trong câu trả lời của mikel, nhưng thiết lập của nó khá quá mức đối với các trường hợp đơn giản, đặc biệt là khi thừa kế phạm vi có sẵn cho bạn. Và, dịch vụ sẽ tồn tại trong toàn bộ vòng đời của ứng dụng của bạn, có thể không phải thứ bạn muốn hoặc cần.

IMHO, $ emit/$ hoạt động khá tốt trong trường hợp của bạn. Thiết lập không quá nặng, phạm vi được tách riêng độc đáo và tất cả các sửa đổi đối với mô hình được tập trung trong RootCtrl, điều này rất tốt cho việc bảo trì mà tôi nghĩ. Nếu bạn lo ngại về những sai lầm bạn có thể thực hiện khi nhập tên sự kiện, bạn có thể tạo hằng số cho tên sự kiện bằng cách sử dụng module.constant(), sau đó sử dụng các hằng số đó thay vì nhập tên sự kiện dưới dạng chuỗi mọi lúc.