$ Scope. $ Emit ve $ scope. $ On ile çalışma


887

Nesnemi ve yöntemlerini $scopekullanarak bir denetleyiciden diğerine nasıl gönderebilirim ?.$emit.$on

function firstCtrl($scope) {
    $scope.$emit('someEvent', [1,2,3]);
}

function secondCtrl($scope) {
    $scope.$on('someEvent', function(mass) { console.log(mass); });
}

Olması gerektiği gibi çalışmıyor. Nasıl $emitve $onçalışır?


6
Sadece gelecekteki okuyucular için: $rootScopekaçınılabileceği durumlarda yayın / yayın için kullanmayın.
Mistalis

Yanıtlar:


1499

Her şeyden önce, ebeveyn-çocuk kapsam ilişkisi önemlidir. Bir etkinlik yayınlamak için iki olasılığınız vardır:

  • $broadcast - etkinliği tüm alt kapsamlara aşağıya gönderir,
  • $emit - olayı, kapsam hiyerarşisinde yukarı doğru gönderir.

Denetleyiciler (kapsamlar) ilişkiniz hakkında hiçbir şey bilmiyorum, ancak birkaç seçenek var:

  1. Kapsamı Eğer firstCtrlüstüdür secondCtrlkapsamı, kodunuz değiştirerek çalışması gerekir $emitgöre $broadcastde firstCtrl:

    function firstCtrl($scope)
    {
        $scope.$broadcast('someEvent', [1,2,3]);
    }
    
    function secondCtrl($scope)
    {
        $scope.$on('someEvent', function(event, mass) { console.log(mass); });
    }
  2. Kapsamlarınız arasında ebeveyn-çocuk ilişkisi yoksa $rootScope, denetleyiciye enjekte edebilir ve olayı tüm çocuk kapsamlarına yayınlayabilirsiniz (örneğin secondCtrl).

    function firstCtrl($rootScope)
    {
        $rootScope.$broadcast('someEvent', [1,2,3]);
    }
  3. Son olarak, olayı alt denetleyiciden kapsamlara yukarı doğru göndermeniz gerektiğinde kullanabilirsiniz $scope.$emit. Kapsamı kapsamın firstCtrlüst secondCtrlöğesiyse:

    function firstCtrl($scope)
    {
        $scope.$on('someEvent', function(event, data) { console.log(data); });
    }
    
    function secondCtrl($scope)
    {
        $scope.$emit('someEvent', [1,2,3]);
    }

8
Bir olayı bir hizmetten bir denetleyiciye göndermenin bir yolu var mı?
Zlatko

29
Evet teorik olarak $rootScopehizmetinize enjekte edebilir ve etkinliği hizmetten yayınlayabilirsiniz.
Ocak'ta zbynour

13
@Zlatko Hizmetlerin varsayılan olarak kapsamsız olduğundan ve etkinlik sistemine katılmak için bir kapsama ihtiyacınız olduğundan eminim. Yani bir şekilde hizmetinize bir kapsam sağlamanız gerekiyor. $ rootScope bunun için en genel amaçlı çözümdür, ancak hizmetinizin farklı bir kapsamdan etkinlik göndermesini istiyorsanız, denetleyiciniz hizmet üzerinde bir özellik ayarlayarak kapsamını hizmete geçirebilir ve şimdi hizmet denetleyicinin kapsamı. Denetleyicinin, hizmete doğrudan çağırabileceği hizmete bir işlev sağlaması için daha basit bir teknik olabilir.
Oran Dennison

3
Bir iframe kullanıyorsanız, bu makale faydalı olacaktır charemza.name/blog/posts/angularjs/iframe/…
leticia

1
Hizmetler enjekte edebilir $rootScope- ancak bir hizmetten (kapalı $rootScope) bir olay yayarsam, o etkinliğin hala devam edeceğini bilmek istiyorum $rootScope; ÇÜNKÜ, $broadcasthiyerarşiyi $emitAŞAĞIYOR ve YUKARI - "YUKARI" ve "AŞAĞI ARASINDAKİ ne olur?" Etkinliğin TÜM "UPWARD" ve TÜM "DOWNWARD" kapsamlarına sessiz olmasını istiyor, ancak yalnızca dağıtım programıyla aynı düzeyde 'duyulabilir' olursam ne olur?
Cody

145

Ayrıca @ zbynour tarafından önerilen seçeneklere daha iyi bir alternatif olarak 4. bir seçenek öneriyoruz.

Kullanım $rootScope.$emityerine $rootScope.$broadcastbakılmaksızın trasmitting ve denetleyici alıcı arasındaki ilişkinin. Bu şekilde, olay küme içinde kalır, $rootScope.$$listenersancak $rootScope.$broadcastolay büyük olasılıkla yine de olayın dinleyicisi olmayacak olan tüm çocuk kapsamlarına yayılır. Ve elbette alıcı denetleyicinin sonunda sadece kullanıyorsunuz $rootScope.$on.

Bu seçenek için denetleyicinin rootScope dinleyicilerini yok etmeyi unutmayın:

var unbindEventHandler = $rootScope.$on('myEvent', myHandler);
$scope.$on('$destroy', function () {
  unbindEventHandler();
});

3
Bu daha sonra temel olarak merkezi bir olay veri yolu olarak hizmet eder mi?
jusopi

5
Bir anlamda evet, yararı olay yayılmasından kaçınmanızdır.
Thalis K.

3
@ThalisK. bu seçenek için teşekkürler. Yayılmayı önler, ancak öte yandan $rootScopekontrolörlere enjeksiyon gerektirir (genel olarak gerekli değildir). Ama kesinlikle başka bir seçenek, teşekkürler!
zbynour

77
$ RootScope'un sonsuza kadar yaşadığına dikkat edin. Denetleyiciniz iki kez çalıştırılırsa, içindeki herhangi bir $ rootScope. $ İki kez çalıştırılır ve yakalanan olaylar iki kez geri çağrıyla sonuçlanır. Bunun yerine $ scope. $ On kullanırsanız, geri arama denetleyicinizle birlikte AngularJS tarafından örtük olarak yok edilir.
Filip Sobczak

1
@FilipSobczak yorumuna göre, $ destroy olayındaki işleyiciyi aşağıdaki kodla jsfiddle.net/ndqexjsg/1
Krzysztof Grzybek

111

. $ Emit ve. $ Yöntemlerini kullanarak $ scope nesnesimi bir denetleyiciden diğerine nasıl gönderebilirim?

$ Scope dahil, uygulamanızın hiyerarşisinde istediğiniz herhangi bir nesneyi gönderebilirsiniz .

İşte nasıl hakkında hızlı bir fikir yayın ve yayarlar çalışması.

Aşağıdaki düğümlere dikkat edin; tüm düğüm 3. kullanmak içinde yuvalanmış yayını ve EMIT Bu senaryoyu varken.

Not: Bu örnekteki her düğümün sayısı isteğe bağlıdır; kolayca bir numara olabilir; iki numara; hatta 1,348 sayısını. Her sayı bu örnek için sadece bir tanımlayıcıdır. Bu örneğin amacı, Açısal denetleyicilerin / direktiflerin iç içe geçmesini göstermektir.

                 3
           ------------
           |          |
         -----     ------
         1   |     2    |
      ---   ---   ---  ---
      | |   | |   | |  | |

Bu ağaca bak. Aşağıdaki soruları nasıl cevaplıyorsunuz?

Not: Bu soruları yanıtlamanın başka yolları da vardır, ancak burada yayını tartışacağız ve yayınlayacağız . Ayrıca, aşağıdaki metni okurken, her sayının kendi dosyası (yönerge, denetleyici) ex one.js, two.js, three.js olduğunu varsayalım.

Düğüm 1 , düğüm 3 ile nasıl konuşur ?

One.js dosyasında

scope.$emit('messageOne', someValue(s));

Three.js dosyasında - iletişim kurmak için tüm alt düğümlere en üstteki düğüm.

scope.$on('messageOne', someValue(s));

Düğüm 2, düğüm 3 ile nasıl konuşur?

Two.js dosyasında

scope.$emit('messageTwo', someValue(s));

Three.js dosyasında - iletişim kurmak için tüm alt düğümlere en üstteki düğüm.

scope.$on('messageTwo', someValue(s));

Düğüm 3, düğüm 1 ve / veya düğüm 2 ile nasıl konuşur?

Three.js dosyasında - iletişim kurmak için tüm alt düğümlere en üstteki düğüm.

scope.$broadcast('messageThree', someValue(s));

Dosyasında one.js && two.js hangisi dosya mesajı veya her ikisini yakalamak istiyorum.

scope.$on('messageThree', someValue(s));

Düğüm 2, düğüm 1 ile nasıl konuşur?

Two.js dosyasında

scope.$emit('messageTwo', someValue(s));

Three.js dosyasında - iletişim kurmak için tüm alt düğümlere en üstteki düğüm.

scope.$on('messageTwo', function( event, data ){
  scope.$broadcast( 'messageTwo', data );
});

One.js dosyasında

scope.$on('messageTwo', someValue(s));

ANCAK

Tüm bu iç içe geçmiş alt düğümler bu şekilde iletişim kurmaya çalıştığında, birçok $ on , $ broadcast ve $ emit'in .

İşte yapmaktan hoşlandığım şey.

En üstteki VELİ NODU'nda ( 3Üst denetleyiciniz olabilecek bu durumda ...) ...

Yani, three.js dosyasında

scope.$on('pushChangesToAllNodes', function( event, message ){
  scope.$broadcast( message.name, message.data );
});

Şimdi alt düğümlerin herhangi birinde $ iletiyi yayınlamanız veya $ on kullanarak yakalamanız yeterlidir .

NOT: Normalde $ emit , $ broadcast veya $ on kullanmadan iç içe bir yolda çapraz konuşmayı yapmak oldukça kolaydır , bu da çoğu kullanım durumunun düğüm 1 ile düğüm 2 arasında iletişim kurmaya çalıştığınız veya tam tersi olduğu anlamına gelir .

Düğüm 2, düğüm 1 ile nasıl konuşur?

Two.js dosyasında

scope.$emit('pushChangesToAllNodes', sendNewChanges());

function sendNewChanges(){ // for some event.
  return { name: 'talkToOne', data: [1,2,3] };
}

Three.js dosyasında - iletişim kurmak için tüm alt düğümlere en üstteki düğüm.

Bunu zaten hallettik hatırlıyor musun?

One.js dosyasında

scope.$on('talkToOne', function( event, arrayOfNumbers ){
  arrayOfNumbers.forEach(function(number){
    console.log(number);
  });
});

Yine de yakalamak istediğiniz her bir değerle $ on kullanmanız gerekecek , ancak şimdi yakalayıp yayınlarken iletiyi üst düğüm boşluğu boyunca nasıl alacağınız konusunda endişelenmenize gerek kalmadan düğümlerden herhangi birinde istediğinizi oluşturabilirsiniz. genel pushChangesToAllNodes .

Bu yardımcı olur umarım...


hangisinin 3,2 ve 1 olduğuna nasıl karar verilir?
HIRA THAKUR

3, 2 ve 1 yuvalanmış denetleyiciler veya yönergelerdir. Uygulamanızı oluştururken, yuvalamanızı unutmayın ve yukarıdaki mantığı uygulayın. Bir örnek olarak, 3'ün uygulamanın $ rootScope'u olduğunu söyleyebiliriz; ve her şey onun altında yuvalanmış. 3, 2 ve 1 keyfidir.
SoEzPz

Harika örnekler! Ancak yine de , denetleyici grubunu iletmek için ebeveynte kendi olay göndericisini kullanmanın daha iyi olduğunu düşünüyorum . Ayrıca, dağıtıcının oluşturulmasını desen olarak kullanmak için hizmet olarak tutmak da yararlıdır.
DenisKolodin

1
$ Broadcast üzerindeki açısal dokümanlara göre, The event life cycle starts at the scope on which $broadcast was called. All listeners listening for name event on this scope get notified. ctrl1 ile ctrl2 ile ctrl2 ile konuşuyorsanız, (benim gibi) sonsuz bir döngü elde $on('x', function(e, data) { $broadcast('x', data) })edersiniz. Yayın yapmadan önce bu hatlara ihtiyacınız olacak; if (e.targetScope.$id === $scope.$id) { return; }
Renato Gama

39

Göndermek için $scope objectbaşka bir denetleyicisinden, ben yaklaşık tartışacağız $rootScope.$broadcastve $rootScope.$emiten çok kullanılan burada.

Durum 1 :

. $ RootScope $ yayın: -

$rootScope.$broadcast('myEvent',$scope.data);//Here `myEvent` is event name

$rootScope.$on('myEvent', function(event, data) {} //listener on `myEvent` event

$rootScopedinleyici otomatik olarak yok edilmez. Bunu kullanarak yok etmelisin $destroy. $scope.$onDinleyiciler $scopeotomatik olarak yok edildiğinde, yani $ kapsamı yok edilir edilmez kullanmak daha iyidir .

$scope.$on('myEvent', function(event, data) {}

Veya,

  var customeEventListener = $rootScope.$on('myEvent', function(event, data) {

  }
  $scope.$on('$destroy', function() {
        customeEventListener();
  });

Durum 2:

. $ RootScope EMIT, $:

   $rootScope.$emit('myEvent',$scope.data);

   $rootScope.$on('myEvent', function(event, data) {}//$scope.$on not works

$ Emit ve $ broadcast'deki en büyük fark $ rootScope. $ Emit olayının $ rootScope. $ On kullanılarak dinlenmesi gerektiğidir, çünkü yayılan olay hiçbir zaman kapsam ağacından aşağı inmez. .
Bu durumda, $ yayın durumunda olduğu gibi dinleyiciyi de yok etmelisiniz.

Düzenle:

Ben kullanmamayı tercih $rootScope.$broadcast + $scope.$onama kullanımı $rootScope.$emit+ $rootScope.$on. $rootScope.$broadcast + $scope.$onKombo ciddi performans sorunlarına neden olabilir. Bunun nedeni, olayın tüm kapsamlarda aşağı ineceği.

Düzenleme 2 :

Bu yanıtta ele alınan sorun angular.js sürüm 1.2.7'de giderilmiştir. $ broadcast şimdi kayıtdışı kapsamlar üzerinde kabarcık oluşmasını önler ve $ emit kadar hızlı çalışır.


10

Aynı uygulamadaki denetleyiciler arasında olay göndermek ve yakalamak için $ rootScope kullanmanız gerekir. Denetleyicilerinize $ rootScope bağımlılığını enjekte edin. İşte çalışan bir örnek.

app.controller('firstCtrl', function($scope, $rootScope) {        
        function firstCtrl($scope) {
        {
            $rootScope.$emit('someEvent', [1,2,3]);
        }
}

app.controller('secondCtrl', function($scope, $rootScope) {
        function secondCtrl($scope)
        {
            $rootScope.$on('someEvent', function(event, data) { console.log(data); });
        }
}

$ Scope nesnesine bağlı olaylar yalnızca sahip denetleyicisinde çalışır. Denetleyiciler arasındaki iletişim $ rootScope veya Services aracılığıyla yapılır.


7

Denetleyicinizden bir söz veren bir hizmeti arayabilir ve daha sonra denetleyicinizde kullanabilirsiniz. Ve daha fazla kullanın $emitveya $broadcastdiğer denetleyicileri bu konuda bilgilendirin. Benim durumumda, servisim aracılığıyla http aramaları yapmak zorunda kaldım, bu yüzden böyle bir şey yaptım:

function ParentController($scope, testService) {
    testService.getList()
        .then(function(data) {
            $scope.list = testService.list;
        })
        .finally(function() {
            $scope.$emit('listFetched');
        })


    function ChildController($scope, testService) {
        $scope.$on('listFetched', function(event, data) {
            // use the data accordingly
        })
    }

ve hizmetim şöyle görünüyor

    app.service('testService', ['$http', function($http) {

        this.list = [];

        this.getList = function() {
            return $http.get(someUrl)
                .then(function(response) {
                    if (typeof response.data === 'object') {
                        list = response.data.results;

                        return response.data;
                    } else {
                        // invalid response
                        return $q.reject(response.data);
                    }

                }, function(response) {
                    // something went wrong
                    return $q.reject(response.data);
                });

        }

    }])

4

Bu benim fonksiyonum:

$rootScope.$emit('setTitle', newVal.full_name);

$rootScope.$on('setTitle', function(event, title) {
    if (scope.item) 
        scope.item.name = title;
    else 
        scope.item = {name: title};
});

1
Bence rootScope'unuz darmadağın olacağından bu kötü bir uygulamadır. Bkz. Stackoverflow.com/questions/24830679/…
SKuijers

4
<!DOCTYPE html>
<html>

<head>
<script src= "http://ajax.googleapis.com/ajax/libs/angularjs/1.3.14/angular.min.js"></script>
<script>
var app = angular.module('MyApp',[]);
app.controller('parentCtrl',function($scope){
  $scope.$on('MyEvent',function(event,data){    
    $scope.myData = data;
  });
 });

app.controller('childCtrl',function($scope){
  $scope.fireEvent = function(){ 
  $scope.$emit('MyEvent','Any Data');
  }  
 });
</script>
</head>
<body ng-app="MyApp">
<div ng-controller="parentCtrl" ng-model="myName">

{{myData}}

 <div ng-controller="childCtrl">
   <button ng-click="fireEvent()">Fire Event</button>
 </div>

</div>
</body>
</html>

2

Kapsam (lar), olayı çocuklara veya ebeveyne yaymak, göndermek için kullanılabilir.

$ emit - etkinliği üst öğeye yayar . $ broadcast - etkinliği çocuklara yayar. dolar - $ emit ve $ broadcast tarafından yayılan olayları dinleme yöntemi.

örnek index.html :

<div ng-app="appExample" ng-controller="EventCtrl">
      Root(Parent) scope count: {{count}}
  <div>
      <button ng-click="$emit('MyEvent')">$emit('MyEvent')</button>
      <button ng-click="$broadcast('MyEvent')">$broadcast('MyEvent')</button><br>

      Childrent scope count: {{count}} 
  </div>
</div>

örnek app.js :

angular.module('appExample', [])
.controller('EventCtrl', ['$scope', function($scope) {
  $scope.count = 0;
  $scope.$on('MyEvent', function() {
    $scope.count++;
  });
}]);

Burada kodu test edebilirsiniz: http://jsfiddle.net/zp6v0rut/41/


2

Aşağıdaki kod, olayların üst denetleyiciye (rootScope) yukarı gönderildiği iki alt denetleyiciyi gösterir

<body ng-app="App">

    <div ng-controller="parentCtrl">

        <p>City : {{city}} </p>
        <p> Address : {{address}} </p>

        <div ng-controller="subCtrlOne">
            <input type="text" ng-model="city" />
            <button ng-click="getCity(city)">City !!!</button>
        </div>

        <div ng-controller="subCtrlTwo">

            <input type="text" ng-model="address" />
            <button ng-click="getAddrress(address)">Address !!!</button>

        </div>

    </div>

</body>

var App = angular.module('App', []);

// parent controller
App.controller('parentCtrl', parentCtrl);

parentCtrl.$inject = ["$scope"];

function parentCtrl($scope) {

    $scope.$on('cityBoom', function(events, data) {
        $scope.city = data;
    });

    $scope.$on('addrBoom', function(events, data) {
        $scope.address = data;
    });
}

// sub controller one

App.controller('subCtrlOne', subCtrlOne);

subCtrlOne.$inject = ['$scope'];

function subCtrlOne($scope) {

    $scope.getCity = function(city) {

        $scope.$emit('cityBoom', city);    
    }
}

// sub controller two

App.controller('subCtrlTwo', subCtrlTwo);

subCtrlTwo.$inject = ["$scope"];

function subCtrlTwo($scope) {

    $scope.getAddrress = function(addr) {

        $scope.$emit('addrBoom', addr);   
    }
}

http://jsfiddle.net/shushanthp/zp6v0rut/


0

Angularjs olay belgelerine göre, alıcı sonda aşağıdaki gibi bir yapıya sahip argümanlar içermelidir

@params

- {Object} olayı, olay hakkında bilgi içeren olay nesnesidir

- Callee tarafından iletilen {Object} bağımsız değişkenleri (Bunun her zaman bir sözlük nesnesine göndermek için yalnızca bir tane daha iyi olabileceğini unutmayın)

$scope.$on('fooEvent', function (event, args) { console.log(args) }); Kodunuzdan

Ayrıca, farklı kontrolörler arasında paylaşılan bir bilgi parçası almaya çalışıyorsanız, bunu elde etmenin başka bir yolu daha vardır ve bu da açısal hizmetlerdir.Hizmetler tekil olduğu için, kontrolörler arasında bilgi depolanabilir ve getirilebilir. bu hizmetteki ayarlayıcı işlevleri, bu işlevleri gösterme, hizmette genel değişkenler oluşturma ve bilgileri depolamak için kullanma


0

En kolay yol :

HTML

  <div ng-app="myApp" ng-controller="myCtrl"> 

        <button ng-click="sendData();"> Send Data </button>

    </div>

JavaScript

    <script>
        var app = angular.module('myApp', []);
        app.controller('myCtrl', function($scope, $rootScope) {
            function sendData($scope) {
                var arrayData = ['sam','rumona','cubby'];
                $rootScope.$emit('someEvent', arrayData);
            }

        });
        app.controller('yourCtrl', function($scope, $rootScope) {
            $rootScope.$on('someEvent', function(event, data) {
                console.log(data); 
            }); 
        });
    </script>
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.