Mở rộng Chỉ thị Angular


114

Tôi muốn thực hiện một sửa đổi nhỏ đối với chỉ thị của bên thứ 3 (cụ thể là Angular UI Bootstrap ). Tôi chỉ muốn thêm vào phạm vi của panechỉ thị:

angular.module('ui.bootstrap.tabs', [])
.controller('TabsController', ['$scope', '$element', function($scope, $element) {
  // various methods
}])
.directive('tabs', function() {
  return {
    // etc...
  };
})
.directive('pane', ['$parse', function($parse) {
  return {
    require: '^tabs',
    restrict: 'EA',
    transclude: true,
    scope:{
      heading:'@',
      disabled:'@' // <- ADDED SCOPE PROPERTY HERE
    },
    link: function(scope, element, attrs, tabsCtrl) {
      // link function
    },
    templateUrl: 'template/tabs/pane.html',
    replace: true
  };
}]);

Nhưng tôi cũng muốn cập nhật Angular-Bootstrap với Bower. Ngay sau khi tôi chạy bower update, tôi sẽ ghi đè các thay đổi của mình.

Vậy làm cách nào để mở rộng chỉ thị này một cách riêng biệt với thành phần bower này?


2
Cách sạch nhất sẽ là sử dụng $provide.decorator(), hãy xem câu trả lời của tôi bên dưới.
Eliran Malka

Câu trả lời:


96

Có lẽ cách đơn giản nhất để giải quyết vấn đề này là tạo một chỉ thị trên ứng dụng của bạn có cùng tên với chỉ thị của bên thứ ba. Cả hai lệnh sẽ chạy và bạn có thể chỉ định thứ tự chạy của chúng bằng cách sử dụng thuộc prioritytính (ưu tiên cao hơn chạy trước).

Hai chỉ thị sẽ chia sẻ phạm vi và bạn có thể truy cập và sửa đổi phạm vi của chỉ thị bên thứ ba thông qua linkphương thức của chỉ thị của bạn .

Tùy chọn 2: Bạn cũng có thể truy cập phạm vi chỉ thị của bên thứ ba bằng cách chỉ cần đặt chỉ thị được đặt tên tùy ý của riêng bạn trên cùng một phần tử với nó (giả sử không chỉ thị nào sử dụng phạm vi cô lập). Tất cả các chỉ thị phạm vi không cô lập trên một phần tử sẽ chia sẻ phạm vi.

Đọc thêm: https://github.com/angular/angular.js/wiki/Dev-Guide%3A-Undilities-Directives

Lưu ý: Câu trả lời trước đây của tôi là để sửa đổi dịch vụ của bên thứ ba, không phải là một chỉ thị.


3
cảm ơn @ sh0ber, đây chính xác là những gì tôi cần. Và câu trả lời trước đây của bạn cũng đã giúp tôi, re: các dịch vụ của bên thứ 3.
Kyle

Này, câu trả lời này thực sự tốt, nhưng tôi không thể tìm thấy bất kỳ tài liệu nào về thuộc tính "ưu tiên" cho các chỉ thị. Tất cả những gì tôi tìm thấy là một lời đồn thổi rằng "bạn có thể sử dụng nó", nhưng không thể tìm thấy bất kỳ ví dụ thực tế nào về nó.
Ciel

2
@Ciel Thông tin API chỉ thị dường như đã được chuyển đến $compiletài liệu ở đây
Dan

60

TL; DR - gimme tha demo!


     Big Demo Button     
 


Sử dụng $provide'sdecorator() để, tốt, trang trí chỉ thị của bên thứ ba.

Trong trường hợp của chúng tôi, chúng tôi có thể mở rộng phạm vi của chỉ thị như vậy:

app.config(function($provide) {
    $provide.decorator('paneDirective', function($delegate) {
        var directive = $delegate[0];
        angular.extend(directive.scope, {
            disabled:'@'
        });
        return $delegate;
    });
});

Đầu tiên, chúng tôi yêu cầu trang trí panechỉ thị bằng cách chuyển tên của nó, được nối với Directivelàm đối số đầu tiên, sau đó chúng tôi truy xuất nó từ tham số gọi lại (là một mảng các chỉ thị khớp với tên đó).

Khi chúng ta có nó, chúng ta có thể lấy đối tượng phạm vi của nó và mở rộng nó khi cần. Lưu ý rằng tất cả những điều này phải được thực hiện trong configkhối.

Một số lưu ý

  • Người ta đề xuất chỉ cần thêm một chỉ thị có cùng tên, sau đó đặt mức độ ưu tiên của nó. Ngoài việc không có ngữ nghĩa ( thậm chí không phải là một từ , tôi biết…), nó còn đặt ra các vấn đề, ví dụ: điều gì sẽ xảy ra nếu mức độ ưu tiên của chỉ thị bên thứ ba thay đổi?

  • JeetendraChauhan đã tuyên bố (tôi chưa thử nghiệm nó) rằng giải pháp này sẽ không hoạt động trong phiên bản 1.13.


1
tôi đề nghị bạn cho câu trả lời của @ sh0ber (tạo một chỉ thị khác chỉ dành cho các sự kiện phát ra).
Eliran Malka

2
Ghi chú nhanh về câu trả lời này (hoạt động tốt), 'Chỉ thị' trong 'paneDirective' thực sự có mục đích ;-) Tôi đã mất một lúc trước khi tìm ra: stackoverflow.com/questions/19409017/… , hãy xem câu trả lời được chấp nhận câu trả lời.
Roy Milder

2
hi @EliranMalka kiểm tra plunker tôi plnkr.co/edit/0mvQjHYjQCFS6joYJdwK hy vọng sẽ giúp đỡ này một người nào đó
Jeetendra Chauhan

1
Liên kết tới decorator()bị hỏng (cập nhật lên docs.angularjs.org/api/auto/service/$provide#decorator )
Chris Brown

1
@EliranMalka vâng, bindToControllerđã được giới thiệu trong v1.3. Nhưng lưu ý rằng đây không được coi là một giải pháp thay thế, điều này chỉ dành cho một trường hợp cụ thể khi chỉ thị ban đầu được thiết lập với bindToControllertài sản. Ý kiến ​​hay, tôi sẽ đăng cái này như một câu trả lời :)
Gilad mayani

8

Mặc dù đây không phải là câu trả lời trực tiếp cho câu hỏi của bạn, nhưng bạn có thể muốn biết rằng phiên bản mới nhất (ở chế độ chính) của http://angular-ui.github.io/bootstrap/ đã thêm hỗ trợ vô hiệu hóa các tab. Tính năng này đã được thêm vào qua: https://github.com/angular-ui/bootstrap/commit/2b78dd16abd7e09846fa484331b5c35ece6619a2


+1 cho những người đứng đầu. tốt để biết. tôi đoán là angle-bootstrap của bower và thành phần bootstrap của angle-ui không đồng bộ.
Kyle

6

Một giải pháp khác trong đó bạn tạo một chỉ thị mới để mở rộng nó mà không cần sửa đổi chỉ thị ban đầu

Giải pháp tương tự như giải pháp trang trí:

Tạo một chỉ thị mới và đưa vào chỉ thị phụ thuộc mà bạn muốn mở rộng

app.directive('extendedPane', function (paneDirective) {

  // to inject a directive as a service append "Directive" to the directive name
  // you will receive an array of directive configurations that match this 
  // directive (usually only one) ordered by priority

  var configExtension = {
     scope: {
       disabled: '@'
     }
  }

  return angular.merge({}, paneDirective[0], configExtension)
});

Bằng cách này, bạn có thể sử dụng chỉ thị gốc và phiên bản mở rộng trong cùng một ứng dụng


2
Điều này thật tuyệt, chỉ là những gì tôi cần để mở rộng chỉ thị phạm vi cô lập với các biến của riêng tôi !! Tôi đã nhận thấy rằng angle.extend không sao chép sâu các đối tượng, vì vậy điều này thay thế đối tượng phạm vi của paneDirective bằng đối tượng này. Một giải pháp thay thế là angle.merge sẽ giữ phạm vi ban đầu khỏi PaneDirective và thêm / hợp nhất các biến được xác định ở đây.
mathewguest

1
vâng, angular.mergelẽ ra phải được sử dụng, tôi sẽ cập nhật ví dụ này
kidroca

1

Đây là một giải pháp khác cho một kịch bản khác về việc mở rộng ràng buộc với một chỉ thị có thuộc bindToControllertính.

Lưu ý: đây không phải là một giải pháp thay thế cho các giải pháp khác đã được cung cấp ở đây. Nó chỉ giải quyết một trường hợp cụ thể (không được đề cập trong các câu trả lời khác) mà chỉ thị ban đầu được thiết lập với bindToController.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.