$ on und $ Broadcast im Winkel

282

Ich habe einen footerController und einen codeScannerController mit unterschiedlichen Ansichten.

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

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

Wenn ich <li>in footer.html auf a klicke, sollte dieses Ereignis in codeScannerController angezeigt werden.

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

Ich denke, es kann mit $onund realisiert werden $broadcast, aber ich weiß nicht wie und kann nirgendwo Beispiele finden.

Alice Polansky
quelle

Antworten:

631

Wenn Sie Folgendes $broadcastverwenden möchten $rootScope:

$scope.startScanner = function() {

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

Und um dann zu empfangen, verwenden Sie die $scopeIhres Controllers:

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

    // do what you want to do
});

Wenn Sie möchten, können Sie Argumente übergeben, wenn Sie $broadcast:

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

Und dann empfange sie:

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

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

Dokumentation hierzu in den Scope-Dokumenten .

Davin Tryon
quelle
2
Sie können das Ereignis beliebig benennen.
Davin Tryon
5
Stellen Sie sicher, dass Sie $ scope sind. $ Apply (); Ihre Änderungen!
Ismail
4
@Ismail Warum ... und wo?
Jaans
7
Gibt es empfohlene Vorgehensweisen zum Speichern dieser Zeichenfolgen, anstatt die Broadcast-Nachricht fest zu codieren?
Wiederholung
8
@Ismail $scope.$apply()ist nur erforderlich, wenn das Modell außerhalb des eckigen Frameworks geändert wird (wie in einem setTimeout, einem Dialogrückruf oder einem Ajax-Rückruf), dh $apply()bereits ausgelöst wird, nachdem der gesamte Codeing abgeschlossen .$on()ist.
th3uiguy
97

Zunächst wird eine kurze Beschreibung $on(), $broadcast()und$emit() :

  • .$on(name, listener) - Hört auf ein bestimmtes Ereignis durch eine bestimmte name
  • .$broadcast(name, args)- Senden Sie eine Veranstaltung durch $scopealle Kinder
  • .$emit(name, args)- Senden Sie ein Ereignis in der $scopeHierarchie an alle Eltern, einschließlich der$rootScope

Basierend auf folgendem HTML (siehe vollständiges Beispiel hier ):

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

Die ausgelösten Ereignisse durchlaufen $scopesFolgendes:

  • Broadcast 1 - Wird nur von Controller 1 gesehen $scope
  • Emit 1 - Wird durch den Controller 1 ist ersichtlich, $scopedann$rootScope
  • Broadcast 2 - Wird von Controller 2 und $scopedann von Controller 3 gesehen$scope
  • Emit 2 - Wird durch den Controller 2 ersichtlich ist $scopedann$rootScope
  • Broadcast 3 - Wird nur von Controller 3 gesehen $scope
  • Emit 3 - Wird durch Regler 3 zu sehen $scope2, Regler $scopedann$rootScope
  • Broadcast Root - Wird von $rootScopeund $scopevon allen Controllern gesehen (1, 2, dann 3)
  • Emit Root - Wird nur von gesehen $rootScope

JavaScript zum Auslösen von Ereignissen (auch hier sehen Sie ein funktionierendes Beispiel ):

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');
    });
}]);
th3uiguy
quelle
Wie kann ich mir die Hierarchie meiner App anhand des von Ihnen angegebenen Beispiels vorstellen? Wie kann ein Controller ein Elternteil oder ein Kind sein? Ich versuche zu sagen, dass ich eine Reihe von Zuständen habe, z. LoginCtrl -> homeCrl -> notificationCtrl und so weiter.
HIRA THAKUR
26

Eine Sache, die Sie wissen sollten, ist, dass sich $ prefix auf eine Winkelmethode bezieht. $$ Präfixe beziehen sich auf Winkelmethoden, die Sie vermeiden sollten.

Im Folgenden finden Sie eine Beispielvorlage und ihre Controller. Wir werden untersuchen, wie $ Broadcast / $ On uns dabei helfen kann, das zu erreichen, was wir wollen.

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

Die Controller sind

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

    }
});

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

});

Meine Frage an Sie lautet: Wie geben Sie den Namen an den zweiten Controller weiter, wenn ein Benutzer auf Registrieren klickt? Möglicherweise haben Sie mehrere Lösungen, aber die, die wir verwenden werden, ist die Verwendung von $ Broadcast und $ On.

$ Broadcast vs $ Emit

Welches sollen wir verwenden? $ Broadcast kanalisiert auf alle untergeordneten Dom-Elemente und $ emit kanalisiert die entgegengesetzte Richtung auf alle Vorfahren-Dom-Elemente.

Der beste Weg, um die Entscheidung zwischen $ emit oder $ Broadcast zu vermeiden, besteht darin, vom $ rootScope aus zu kanalisieren und $ Broadcast für alle untergeordneten Elemente zu verwenden. Das macht unseren Fall viel einfacher, da unsere Dom-Elemente Geschwister sind.

Hinzufügen von $ rootScope und Ermöglichen von $ Broadcast

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

Beachten Sie, dass wir $ rootScope hinzugefügt haben und jetzt $ Broadcast (BroadcastName, Argumente) verwenden. Für BroadcastName möchten wir ihm einen eindeutigen Namen geben, damit wir diesen Namen in unserer zweiten Strg abfangen können. Ich habe BOOM gewählt! nur zum Spaß. Das zweite Argument 'Argumente' ermöglicht es uns, Werte an die Listener zu übergeben.

Empfang unserer Sendung

In unserem zweiten Controller müssen wir Code einrichten, um unsere Sendung anzuhören

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

So einfach ist das wirklich. Live-Beispiel

Andere Möglichkeiten, um ähnliche Ergebnisse zu erzielen

Vermeiden Sie die Verwendung dieser Methodensuite, da sie weder effizient noch leicht zu warten ist. Sie können jedoch auf einfache Weise Probleme beheben, die möglicherweise auftreten.

Normalerweise können Sie dasselbe tun, indem Sie einen Dienst verwenden oder Ihre Controller vereinfachen. Wir werden dies nicht im Detail diskutieren, aber ich dachte, ich würde es der Vollständigkeit halber nur erwähnen.

Denken Sie zum Schluss daran, dass eine wirklich nützliche Sendung zum Anhören wieder '$ destroy' ist. Sie können sehen, dass $ bedeutet, dass es sich um eine Methode oder ein Objekt handelt, die von den Herstellercodes erstellt wurden. Auf jeden Fall wird $ destroy gesendet, wenn ein Controller zerstört wird. Möglicherweise möchten Sie dies anhören, um zu erfahren, wann Ihr Controller entfernt wird.

Yang Li
quelle
2
Versuchen Sie als Warnung, nicht zu viele Sendungen / Sendungen in Ihrer App zu verwenden. Insbesondere in einer großen App kann es äußerst schwierig sein, sie zu verwalten, da es sehr schwierig ist, die Wurzeln dieser Ereignisse zu ermitteln.
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();
       };
    }); }());
Sandig
quelle