$ on และ $ ออกอากาศในเชิงมุม


282

ฉันมีส่วนท้ายส่วนท้ายและโค้ดสแกนเนอร์ตัวควบคุมพร้อมมุมมองที่แตกต่างกัน

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

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

เมื่อฉันคลิกที่<li>ใน footer.html ฉันควรได้รับเหตุการณ์นี้ใน codeScannerController

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

ฉันคิดว่ามันสามารถรับรู้ได้ด้วย$onและ$broadcastแต่ฉันไม่รู้วิธีและไม่สามารถหาตัวอย่างได้ทุกที่

คำตอบ:


631

หากคุณต้องการ$broadcastใช้$rootScope:

$scope.startScanner = function() {

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

จากนั้นเพื่อรับใช้$scopeตัวควบคุมของคุณ:

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

    // do what you want to do
});

หากคุณต้องการคุณสามารถส่งผ่านข้อโต้แย้งเมื่อคุณ$broadcast:

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

และจากนั้นรับ:

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

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

เอกสารสำหรับการนี้ภายในเอกสารขอบเขต


2
คุณสามารถตั้งชื่อกิจกรรมอะไรก็ได้ที่คุณชอบ
Davin Tryon

5
ตรวจสอบให้แน่ใจว่าคุณเป็น $ scope $ ใช้ (); การเปลี่ยนแปลงของคุณ!
Ismail

4
@Ismail ทำไม ... และที่ไหน
Jaans

7
มีแนวทางปฏิบัติที่แนะนำสำหรับการจัดเก็บสตริงเหล่านี้ที่ไหนสักแห่งมากกว่าการเข้ารหัสข้อความออกอากาศ?
เริ่ม

8
@Ismail $scope.$apply()จำเป็นเฉพาะเมื่อเปลี่ยนโมเดลนอกกรอบเชิงมุม (เช่นใน setTimeout, callback dialog หรือ ajax callback) ในคำอื่น ๆ$apply()จะถูกเรียกใช้หลังจากรหัสทั้งหมดใน.$on()เสร็จสิ้น
th3uiguy

97

ประการแรกคำอธิบายสั้น ๆ$on(), $broadcast()และ$emit() :

  • .$on(name, listener) - รับฟังเหตุการณ์เฉพาะตามที่กำหนด name
  • .$broadcast(name, args)- ออกอากาศกิจกรรมผ่าน$scopeเด็ก ๆ ทุกคน
  • .$emit(name, args)- ปล่อยเหตุการณ์ขึ้นตาม$scopeลำดับชั้นให้ผู้ปกครองทุกคนรวมถึง$rootScope

ยึดตาม HTML ต่อไปนี้ (ดูตัวอย่างแบบเต็มได้ที่นี่ ):

<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>

เหตุการณ์ที่ถูกยิงจะข้าม$scopesไปดังนี้:

  • Broadcast 1 - ผู้ควบคุม 1 จะเห็นได้เท่านั้น $scope
  • ปล่อย 1 - จะเห็นได้โดยผู้ควบคุม 1 $scopeแล้ว$rootScope
  • Broadcast 2 - ผู้ควบคุม 2 จะเห็นได้จาก$scopeนั้นผู้ควบคุม 3$scope
  • ปล่อย 2 - จะเห็นได้โดยผู้ควบคุม 2 $scopeแล้ว$rootScope
  • Broadcast 3 - จะเห็นได้จากคอนโทรลเลอร์ 3 เท่านั้น $scope
  • ปล่อย 3 - จะเห็นได้จากคอนโทรลเลอร์ 3 $scope, คอนโทรลเลอร์ 2 $scopeแล้ว$rootScope
  • ออกอากาศราก - จะเห็น$rootScopeและ$scopeการควบคุมทั้งหมด (1, 2 แล้ว 3)
  • ปล่อยราก - จะเห็นได้โดย $rootScope

JavaScript เพื่อเรียกใช้เหตุการณ์ (อีกครั้งคุณสามารถดูตัวอย่างการทำงานได้ที่นี่ ):

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');
    });
}]);

ฉันจะจินตนาการถึงลำดับชั้นของแอพของฉันด้วยตัวอย่างที่คุณให้มาได้อย่างไร คอนโทรลเลอร์สามารถเป็นพ่อแม่หรือลูกได้อย่างไร? สิ่งที่ฉันพยายามจะพูดคือฉันมีชุดของรัฐเช่น LoginCtrl -> homeCrl -> notificationCtrl และอื่น ๆ
HIRA THAKUR

26

สิ่งหนึ่งที่คุณควรรู้คือ $ prefix อ้างอิงถึง Angular Method คำนำหน้า $$ หมายถึงวิธีเชิงมุมที่คุณควรหลีกเลี่ยง

ด้านล่างนี้เป็นตัวอย่างเทมเพลตและตัวควบคุมเราจะสำรวจว่า $ broadcast / $ on สามารถช่วยให้เราบรรลุสิ่งที่เราต้องการได้อย่างไร

<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>

ตัวควบคุมคือ

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

    }
});

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

});

คำถามของฉันคือคุณจะส่งชื่อไปยังคอนโทรลเลอร์ที่สองอย่างไรเมื่อผู้ใช้คลิกลงทะเบียน? คุณอาจเกิดปัญหาหลายอย่าง แต่วิธีที่เราจะใช้คือการใช้ $ broadcast และ $ on

$ broadcast เทียบกับ $ emit

เราควรใช้แบบไหน $ Broadcast จะออกอากาศลงไปยังองค์ประกอบของลูกทั้งหมดและ $ emit จะส่งสัญญาณทิศทางตรงข้ามกับองค์ประกอบทั้งหมดของ Dom

วิธีที่ดีที่สุดในการหลีกเลี่ยงการตัดสินใจระหว่าง $ emit หรือ $ broadcast คือการทำช่องทางจาก $ rootScope และใช้ $ broadcast กับลูก ๆ ทุกคน ซึ่งทำให้กรณีของเราง่ายขึ้นมากเนื่องจากองค์ประกอบ dom ของเราเป็นพี่น้อง

เพิ่ม $ rootScope และให้ $ broadcast

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

หมายเหตุเราได้เพิ่ม $ rootScope และตอนนี้เรากำลังใช้ $ broadcast (broadcastName, arguments) สำหรับ BroadcastName เราต้องการตั้งชื่อที่ไม่ซ้ำกันเพื่อให้เราสามารถตรวจจับชื่อนั้นใน secondCtrl ของเรา ฉันเลือกบูมแล้ว! แค่เล่น ๆ. ข้อโต้แย้งที่สอง 'ข้อโต้แย้ง' ช่วยให้เราสามารถส่งผ่านค่าไปยังผู้ฟัง

รับการออกอากาศของเรา

ในตัวควบคุมที่สองของเราเราต้องตั้งค่ารหัสเพื่อฟังการออกอากาศของเรา

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

มันง่ายจริงๆ ตัวอย่างสด

วิธีอื่น ๆ เพื่อให้ได้ผลลัพธ์ที่คล้ายกัน

พยายามหลีกเลี่ยงการใช้ชุดวิธีการนี้เนื่องจากไม่มีประสิทธิภาพหรือบำรุงรักษาง่าย แต่เป็นวิธีง่ายๆในการแก้ไขปัญหาที่คุณอาจมี

โดยปกติคุณสามารถทำสิ่งเดียวกันได้โดยใช้บริการหรือทำให้ตัวควบคุมของคุณง่ายขึ้น เราจะไม่พูดถึงเรื่องนี้ในรายละเอียด แต่ฉันคิดว่าฉันแค่พูดถึงมันเพื่อความสมบูรณ์

สุดท้ายอย่าลืมว่าการออกอากาศที่มีประโยชน์จริงๆที่จะฟังคือ '$ destroy' อีกครั้งคุณจะเห็น $ หมายความว่าเป็นวิธีหรือวัตถุที่สร้างขึ้นโดยรหัสผู้ขาย Anyways $ destroy ถูกออกอากาศเมื่อคอนโทรลเลอร์ถูกทำลายคุณอาจต้องการฟังสิ่งนี้เพื่อรู้ว่าเมื่อใดที่คอนโทรลเลอร์ของคุณถูกลบ


2
คำเตือนอย่าพยายามใช้การออกอากาศ / การส่งเสียงมากเกินไปในแอปของคุณ พวกเขาสามารถจัดการได้ยากมากโดยเฉพาะในแอพขนาดใหญ่เนื่องจากการติดตามรากของเหตุการณ์เหล่านี้เป็นงานที่ยากมาก
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();
       };
    }); }());
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.