$ trên và $ phát sóng trong góc


282

Tôi có một footerControll và codeScannerControll với các khung nhìn khác nhau.

angular.module('myApp').controller('footerController', ["$scope", function($scope) {}]);

angular.module('myApp').controller('codeScannerController', ["$scope", function($scope) {
console.log("start");
$scope.startScanner = function(){...

Khi tôi nhấp vào một <li>footer.html tôi sẽ nhận được sự kiện này trong codeScannerControll.

<li class="button" ng-click="startScanner()">3</li>

Tôi nghĩ rằng nó có thể được nhận ra với $on$broadcast, nhưng tôi không biết làm thế nào và không thể tìm thấy các ví dụ ở bất cứ đâu.

Câu trả lời:


631

Nếu bạn muốn $broadcastsử dụng $rootScope:

$scope.startScanner = function() {

    $rootScope.$broadcast('scanner-started');
}

Và sau đó để nhận, sử dụng $scopebộ điều khiển của bạn:

$scope.$on('scanner-started', function(event, args) {

    // do what you want to do
});

Nếu bạn muốn bạn có thể truyền đối số khi bạn $broadcast:

$rootScope.$broadcast('scanner-started', { any: {} });

Và sau đó nhận được chúng:

$scope.$on('scanner-started', function(event, args) {

    var anyThing = args.any;
    // do what you want to do
});

Tài liệu cho điều này trong các tài liệu Phạm vi .


2
Bạn có thể đặt tên cho sự kiện bất cứ điều gì bạn thích.
Davin Tryon

5
Hãy chắc chắn rằng bạn là $ scope. $ Áp dụng (); những thay đổi của bạn!
Ismail

4
@Ismail Tại sao ... và ở đâu?
Jaans

7
Có bất kỳ thực hành được đề xuất nào để lưu trữ các chuỗi này ở đâu đó thay vì mã hóa thông điệp quảng bá không?
rperryng

8
@Ismail $scope.$apply()chỉ cần thiết khi thay đổi mô hình bên ngoài khung góc (như trong setTimeout, gọi lại hộp thoại hoặc gọi lại ajax), nói cách khác $apply()là đã được kích hoạt sau khi tất cả mã .$on()được kết thúc.
th3uiguy

97

Đầu tiên, một mô tả ngắn về $on(), $broadcast()$emit() :

  • .$on(name, listener) - Lắng nghe một sự kiện cụ thể bằng cách cho name
  • .$broadcast(name, args)- Phát sóng một sự kiện thông qua $scopetất cả trẻ em
  • .$emit(name, args)- Phát ra một sự kiện lên $scopethứ bậc cho tất cả các bậc cha mẹ, bao gồm cả$rootScope

Dựa trên HTML sau (xem ví dụ đầy đủ tại đây ):

<div ng-controller="Controller1">
    <button ng-click="broadcast()">Broadcast 1</button>
    <button ng-click="emit()">Emit 1</button>
</div>

<div ng-controller="Controller2">
    <button ng-click="broadcast()">Broadcast 2</button>
    <button ng-click="emit()">Emit 2</button>
    <div ng-controller="Controller3">
        <button ng-click="broadcast()">Broadcast 3</button>
        <button ng-click="emit()">Emit 3</button>
        <br>
        <button ng-click="broadcastRoot()">Broadcast Root</button>
        <button ng-click="emitRoot()">Emit Root</button>
    </div>
</div>

Các sự kiện bị sa thải sẽ đi qua $scopesnhư sau:

  • Phát sóng 1 - Sẽ chỉ được xem bởi Bộ điều khiển 1 $scope
  • Phát ra 1 - Sẽ được nhìn thấy bởi Bộ điều khiển 1 $scopesau đó$rootScope
  • Phát sóng 2 - Sẽ được xem bởi Bộ điều khiển 2 $scoperồi Bộ điều khiển 3$scope
  • Phát ra 2 - Sẽ được nhìn thấy bởi Bộ điều khiển 2 $scopesau đó$rootScope
  • Phát sóng 3 - Sẽ chỉ được xem bởi Bộ điều khiển 3 $scope
  • Phát ra 3 - Sẽ được nhìn thấy bởi Bộ điều khiển 3 $scope, Bộ điều khiển 2 $scoperồi$rootScope
  • Broadcast Root - Sẽ được xem bởi $rootScope$scopecủa tất cả các Bộ điều khiển (1, 2 rồi 3)
  • Root phát ra - Sẽ chỉ được nhìn thấy bởi $rootScope

JavaScript để kích hoạt các sự kiện (một lần nữa, bạn có thể thấy một ví dụ hoạt động ở đây ):

app.controller('Controller1', ['$scope', '$rootScope', function($scope, $rootScope){
    $scope.broadcastAndEmit = function(){
        // This will be seen by Controller 1 $scope and all children $scopes 
        $scope.$broadcast('eventX', {data: '$scope.broadcast'});

        // Because this event is fired as an emit (goes up) on the $rootScope,
        // only the $rootScope will see it
        $rootScope.$emit('eventX', {data: '$rootScope.emit'});
    };
    $scope.emit = function(){
        // Controller 1 $scope, and all parent $scopes (including $rootScope) 
        // will see this event
        $scope.$emit('eventX', {data: '$scope.emit'});
    };

    $scope.$on('eventX', function(ev, args){
        console.log('eventX found on Controller1 $scope');
    });
    $rootScope.$on('eventX', function(ev, args){
        console.log('eventX found on $rootScope');
    });
}]);

Làm thế nào tôi có thể tưởng tượng thứ bậc của ứng dụng của tôi với ví dụ mà bạn đã đưa ra. Làm thế nào một bộ điều khiển có thể là cha mẹ hoặc con. ?? Điều tôi đang cố gắng nói là tôi có hàng loạt trạng thái, vd. Đăng nhậpCtrl -> homeCrl -> notifyCtrl, v.v.
HIRA THAKUR

26

Một điều bạn nên biết là tiền tố $ đề cập đến Phương thức góc, tiền tố $$ đề cập đến các phương thức góc mà bạn nên tránh sử dụng.

bên dưới là một mẫu ví dụ và bộ điều khiển của nó, chúng ta sẽ khám phá cách $ Broadcast / $ trên có thể giúp chúng ta đạt được những gì chúng ta muốn.

<div ng-controller="FirstCtrl">
    <input ng-model="name"/> 
    <button ng-click="register()">Register </button>
</div>

<div ng-controller="SecondCtrl">
    Registered Name: <input ng-model="name"/> 
</div>

Các bộ điều khiển là

app.controller('FirstCtrl', function($scope){
    $scope.register = function(){

    }
});

app.controller('SecondCtrl', function($scope){

});

Câu hỏi của tôi cho bạn là làm thế nào để bạn chuyển tên cho bộ điều khiển thứ hai khi người dùng nhấp vào đăng ký? Bạn có thể đưa ra nhiều giải pháp nhưng giải pháp chúng tôi sẽ sử dụng là sử dụng $ Broadcast và $ on.

$ phát sóng so với $ phát ra

Chúng ta nên sử dụng cái nào? $ Broadcast sẽ chuyển xuống tất cả các phần tử dom con và $ emit sẽ chuyển hướng ngược lại với tất cả các phần tử dom tổ tiên.

Cách tốt nhất để tránh quyết định giữa $ emit hoặc $ Broadcast là chuyển kênh từ $ rootScope và sử dụng $ Broadcast cho tất cả các con của nó. Điều này làm cho trường hợp của chúng tôi dễ dàng hơn nhiều vì các yếu tố dom của chúng tôi là anh em ruột.

Thêm $ rootScope và cho phép $ phát sóng

app.controller('FirstCtrl', function($rootScope, $scope){
    $scope.register = function(){
        $rootScope.$broadcast('BOOM!', $scope.name)
    }
});

Lưu ý, chúng tôi đã thêm $ rootScope và bây giờ chúng tôi đang sử dụng $ Broadcast (BroadcastName, argument). Đối với BroadcastName, chúng tôi muốn đặt cho nó một tên duy nhất để chúng tôi có thể bắt được tên đó trong secondCtrl của chúng tôi. Tôi đã chọn BÙM! chỉ để cho vui Các đối số thứ hai 'đối số' cho phép chúng ta truyền các giá trị cho người nghe.

Nhận được phát sóng của chúng tôi

Trong bộ điều khiển thứ hai của chúng tôi, chúng tôi cần thiết lập mã để nghe chương trình phát của chúng tôi

app.controller('SecondCtrl', function($scope){
  $scope.$on('BOOM!', function(events, args){
    console.log(args);
    $scope.name = args; //now we've registered!
  })
});

Nó thực sự đơn giản. Ví dụ trực tiếp

Những cách khác để đạt được kết quả tương tự

Cố gắng tránh sử dụng bộ phương pháp này vì nó không hiệu quả cũng không dễ bảo trì nhưng đó là cách đơn giản để khắc phục các sự cố bạn có thể gặp phải.

Bạn thường có thể làm điều tương tự bằng cách sử dụng một dịch vụ hoặc bằng cách đơn giản hóa bộ điều khiển của bạn. Chúng tôi sẽ không thảo luận chi tiết về vấn đề này nhưng tôi nghĩ tôi chỉ muốn đề cập đến nó cho đầy đủ.

Cuối cùng, hãy nhớ rằng một chương trình phát thực sự hữu ích để nghe là '$ hủy' một lần nữa bạn có thể thấy $ có nghĩa là phương thức hoặc đối tượng được tạo bởi mã nhà cung cấp. Dù sao $ phá hủy được phát khi bộ điều khiển bị phá hủy, bạn có thể muốn nghe điều này để biết khi nào bộ điều khiển của bạn bị xóa.


2
Để cảnh báo, hãy cố gắng không sử dụng quá nhiều chương trình phát / phát trong ứng dụng của bạn. Chúng có thể cực kỳ khó quản lý, đặc biệt là trong một ứng dụng lớn vì việc truy tìm nguồn gốc của những sự kiện này là một nhiệm vụ rất khó khăn.
Yang Li

1
//Your broadcast in service

(function () { 
    angular.module('appModule').factory('AppService', function ($rootScope, $timeout) {

    function refreshData() {  
        $timeout(function() {         
            $rootScope.$broadcast('refreshData');
        }, 0, true);      
    }

    return {           
        RefreshData: refreshData
    };
}); }());

//Controller Implementation
 (function () {
    angular.module('appModule').controller('AppController', function ($rootScope, $scope, $timeout, AppService) {            

       //Removes Listeners before adding them 
       //This line will solve the problem for multiple broadcast call                             
       $scope.$$listeners['refreshData'] = [];

       $scope.$on('refreshData', function() {                                                    
          $scope.showData();             
       });

       $scope.onSaveDataComplete = function() { 
         AppService.RefreshData();
       };
    }); }());
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.