$ scope. $ emit 및 $ scope. $ on으로 작업


887

and 메소드를 $scope사용하여 한 컨트롤러에서 다른 컨트롤러로 객체를 보내려면 어떻게 해야합니까?.$emit.$on

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

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

내가 생각하는 방식으로 작동하지 않습니다. 어떻게 $emit하고 $on사용할 수 있습니까?


6
미래의 독자들을 위해서만 : $rootScope피할 수있을 때 브로드 캐스트 / 방출에 사용하지 마십시오 .
Mistalis

답변:


1499

우선, 부모-자식 범위 관계가 중요합니다. 이벤트를 발생시킬 수있는 두 가지 가능성이 있습니다.

  • $broadcast -이벤트를 모든 하위 범위로 하향 전달합니다.
  • $emit -범위 계층 구조를 통해 위쪽으로 이벤트를 전달합니다.

컨트롤러 (범위) 관계에 대해서는 아무것도 모르지만 몇 가지 옵션이 있습니다.

  1. 의 범위는 경우 firstCtrl의 부모 secondCtrl범위는, 당신의 코드를 대체하여 작업을해야 $emit으로 $broadcastfirstCtrl:

    function firstCtrl($scope)
    {
        $scope.$broadcast('someEvent', [1,2,3]);
    }
    
    function secondCtrl($scope)
    {
        $scope.$on('someEvent', function(event, mass) { console.log(mass); });
    }
    
  2. 스코프간에 상위-하위 관계가없는 경우 $rootScope컨트롤러에 주입 하고 모든 하위 범위 (예 :)로 이벤트를 브로드 캐스트 할 수 있습니다 secondCtrl.

    function firstCtrl($rootScope)
    {
        $rootScope.$broadcast('someEvent', [1,2,3]);
    }
    
  3. 마지막으로 자식 컨트롤러에서 이벤트를 범위 내로 전달해야 할 때 사용할 수 있습니다 $scope.$emit. 범위가 범위의 firstCtrl상위 인 경우 secondCtrl:

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

8
서비스에서 컨트롤러로 이벤트를 발생시키는 방법이 있습니까?
Zlatko

29
그렇습니다. 이론적 $rootScope으로 서비스에 주입 하고 서비스에서 이벤트를 브로드 캐스트 할 수 있습니다.
zbynour

13
@Zlatko 기본적으로 서비스는 범위가 없으며 이벤트 시스템에 참여하려면 범위가 필요합니다. 따라서 어떻게 든 서비스 범위를 제공해야합니다. $ rootScope는 그에 대한 가장 일반적인 솔루션이지만, 서비스가 다른 범위에서 이벤트를 보내도록하려면 컨트롤러가 서비스에서 속성을 설정하여 해당 범위를 서비스에 전달하면 이제 서비스에서 컨트롤러의 범위. 컨트롤러가 서비스에 직접 호출 할 수있는 기능을 제공하는보다 간단한 기술이있을 수 있습니다.
Oran Dennison

3
iframe을 사용하는 경우이 기사가 도움이 될 것입니다 charemza.name/blog/posts/angularjs/iframe/…
leticia

1
서비스는 주입 할 수 $rootScope있지만 서비스 $rootScope에서 이벤트를 발생시키는 경우에도 이벤트가 계속 진행됨을 알고 싶습니다 $rootScope. 왜냐하면 브로드 캐스터 / 이미 터가 리스너 (?)이기 때문에 $broadcast계층 구조를 DOWN하고 $emitUP 과 PER을 "UP"과 "DOWN"사이에서 겪는 경우 입니다. 이벤트가 모든 "UPWARD"및 모든 "DOWNWARD"범위에 대해 자동이지만 디스패처와 동일한 레벨에서만 '듣기'만하려면 어떻게해야합니까?
Cody

145

@zbynour의 제안 된 옵션에 대한 더 나은 대안으로 4 번째 옵션을 제안합니다.

사용 $rootScope.$emit보다는 $rootScope.$broadcast없이 trasmitting 컨트롤러 수용의 관계. 그런 식으로 이벤트는 일련의 범위 내에서 유지 $rootScope.$$listeners되지만 $rootScope.$broadcast이벤트는 모든 하위 범위로 전파되며 대부분 해당 이벤트의 리스너가 아닐 것입니다. 물론 수신 컨트롤러의 끝에서는을 사용 $rootScope.$on합니다.

이 옵션을 사용하려면 컨트롤러의 rootScope 리스너를 삭제해야합니다.

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

3
그러면 기본적으로 중앙 이벤트 버스 역할을합니까?
jusopi

5
어떤 의미에서는 그렇습니다. 이벤트 전파를 피한다는 이점이 있습니다.
Thalis K.

3
@ThalisK. 이 옵션에 감사드립니다. 전파를 피하지만 반면 $rootScope컨트롤러에 주입 해야합니다 (일반적으로 필요하지 않은 것). 그러나 또 다른 옵션 인 thx!
zbynour

77
$ rootScope는 영구적으로 유지됩니다. 컨트롤러가 두 번 실행되면 그 안에있는 $ rootScope. $가 두 번 실행되며 잡힌 이벤트로 인해 콜백이 두 번 호출됩니다. 대신 $ scope. $ on을 사용하면 콜백은 컨트롤러와 함께 AngularJS에 의해 암시 적으로 파괴됩니다.
Filip Sobczak

1
@FilipSobczak 의견에 따르면 다음 코드 jsfiddle.net/ndqexjsg/1를
Krzysztof Grzybek

111

. $ emit 및. $ on 메소드를 사용하여 한 컨트롤러에서 다른 컨트롤러로 $ scope 객체를 보내려면 어떻게해야합니까?

$ scope를 포함하여 앱의 계층 구조 내에서 원하는 객체를 보낼 수 있습니다 .

다음은 브로드 캐스트방출 작동 방식에 대한 간단한 아이디어 입니다.

아래 노드를 확인하십시오. 이 시나리오는 브로드 캐스트를 사용 하고 방출 합니다.

참고 : 이 예에서 각 노드의 수는 임의입니다. 그것은 쉽게 1 위가 될 수 있습니다. 두 번째; 또는 심지어 1,348의 숫자. 각 숫자는이 예의 식별자 일뿐입니다. 이 예제의 핵심은 Angular 컨트롤러 / 지시문의 중첩을 보여주는 것입니다.

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

이 나무를 확인하십시오. 다음 질문에 어떻게 대답하십니까?

참고 : 이러한 질문에 대답하는 다른 방법이 있지만 여기서는 broadcastemit에 대해 설명 합니다. 또한 아래 텍스트를 읽을 때 각 숫자에는 one.js, two.js, three.js와 같은 자체 파일 (직접, 컨트롤러)이 있다고 가정합니다.

노드 1 은 노드 3과 어떻게 통신합니까?

파일 one.js에서

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

three.js 파일 -통신에 필요한 모든 하위 노드에 대한 최상위 노드.

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

노드 2는 노드 3과 어떻게 통신합니까?

파일 two.js에서

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

three.js 파일 -통신에 필요한 모든 하위 노드에 대한 최상위 노드.

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

노드 3은 노드 1 및 / 또는 노드 2와 어떻게 통신합니까?

three.js 파일 -통신에 필요한 모든 하위 노드에 대한 최상위 노드.

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

파일 one.js && two.js 에서 메시지를 잡으려는 파일 또는 둘 다.

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

노드 2는 노드 1과 어떻게 통신합니까?

파일 two.js에서

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

three.js 파일 -통신에 필요한 모든 하위 노드에 대한 최상위 노드.

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

파일 one.js에서

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

하나

이러한 중첩 된 자식 노드가 모두 이와 같이 통신하려고하면 많은 $ on , $ broadcast 's$ emit 's 가 빠르게 나타납니다 .

여기 내가 좋아하는 일이 있습니다.

상위 PARENT NODE ( 이 경우 3) 에서 상위 컨트롤러 일 수 있습니다.

따라서 파일 three.js에서

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

이제 모든 하위 노드 에서 메시지 를 $ emit 하거나 $ on을 사용하여 잡기 만하면 됩니다 .

참고 : 일반적으로 $ emit , $ broadcast 또는 $ on 을 사용하지 않고 하나의 중첩 경로에서 대화하기가 매우 쉽습니다. 즉, 대부분의 사용 사례는 노드 1 이 노드 2 와 통신 하거나 그 반대로 통신 하려고 할 때 사용됩니다 .

노드 2는 노드 1과 어떻게 통신합니까?

파일 two.js에서

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

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

three.js 파일 -통신에 필요한 모든 하위 노드에 대한 최상위 노드.

우리는 이미 이것을 기억 했습니까?

파일 one.js에서

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

잡으려는 각 특정 값과 함께 $ on 을 사용해야 하지만 이제는 잡거나 브로드 캐스트 할 때 부모 노드 간격을 넘어서 메시지를 얻는 방법에 대해 걱정할 필요없이 모든 노드에서 원하는 것을 만들 수 있습니다. 일반 pushChangesToAllNodes .

도움이 되었기를 바랍니다...


3, 2 및 1을 결정하는 방법?
HIRA THAKUR

3, 2 및 1은 중첩 된 컨트롤러 또는 지시문입니다. 앱을 만들 때 중첩을 염두에두고 위의 논리를 적용하십시오. 예를 들어 3은 응용 프로그램의 $ rootScope입니다. 모든 것이 그 아래에 중첩되어 있습니다. 3, 2 및 1은 임의적입니다.
SoEzPz

좋은 예! 그러나 여전히 컨트롤러 그룹과 통신하기 위해 부모에서 자체 이벤트 디스패처 를 사용하는 것이 좋습니다 . 디스패처 작성을 패턴으로 사용하기위한 서비스로 작성하는 데에도 유용합니다.
DenisKolodin

1
$ broadcast의 앵귤러 문서에 따르면 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을 ctrl3과 함께 ctrl2와 대화하도록 구현하면 나처럼 무한 루프가 발생합니다 $on('x', function(e, data) { $broadcast('x', data) }). 방송하기 전에이 라인이 필요합니다. if (e.targetScope.$id === $scope.$id) { return; }
Renato Gama

39

보내려면 $scope object한 컨트롤러에서 다른 컨트롤러, I 대해 논의 $rootScope.$broadcast하고 $rootScope.$emit그들이 가장 많이 사용되는 여기에.

사례 1 :

$ rootScope. $ 방송 :-

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

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

$rootScope리스너는 자동으로 삭제되지 않습니다. 를 사용하여 삭제해야합니다 $destroy. $scope.$on리스너 $scope가 자동으로 소멸 될 때, 즉 $ scope가 소멸되는 즉시 사용하는 것이 좋습니다 .

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

또는,

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

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

사례 2 :

$ rootScope. $ 방출 :

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

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

$ emit과 $ broadcast의 주요 차이점은 생성 된 이벤트가 스코프 트리를 통해 내려 가지 않기 때문에 $ rootScope. $ on을 사용하여 $ rootScope. $ emit 이벤트를 수신해야한다는 것입니다. .
이 경우에도 $ broadcast의 경우와 같이 리스너를 삭제해야합니다.

편집하다:

나는 사용하는 $rootScope.$broadcast + $scope.$on것이 아니라 사용 하는 것을 선호 합니다 $rootScope.$emit+ $rootScope.$on. $rootScope.$broadcast + $scope.$on콤보는 성능에 심각한 문제가 발생할 수 있습니다. 이벤트가 모든 범위에서 버블 링되기 때문입니다.

편집 2 :

이 답변에서 해결 된 문제는 angular.js 버전 1.2.7에서 해결되었습니다. $ broadcast는 이제 등록되지 않은 범위에서 버블 링을 피하고 $ emit만큼 빠르게 실행됩니다.


10

동일한 앱에서 컨트롤러간에 이벤트를 보내고 캡처하려면 $ rootScope를 사용해야합니다. 컨트롤러에 $ rootScope 종속성을 삽입하십시오. 다음은 실제 예입니다.

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 객체에 연결된 이벤트는 소유자 컨트롤러에서만 작동합니다. 컨트롤러 간의 통신은 $ rootScope 또는 Services를 통해 수행됩니다.


7

약속을 반환하는 컨트롤러에서 서비스를 호출 한 다음이를 컨트롤러에서 사용할 수 있습니다. 추가로 사용 $emit하거나 $broadcast다른 컨트롤러에 알려줍니다. 제 경우에는 서비스를 통해 http 호출을해야하므로 다음과 같이했습니다.

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

내 서비스는 다음과 같습니다

    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

이것은 내 기능입니다.

$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
rootScope가 어수선해질 것이기 때문에 이것이 나쁜 습관이라고 생각합니다. 참조 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

범위를 사용하여 이벤트를 범위 하위 또는 상위로 전달하고 전달할 수 있습니다.

$ emit- 이벤트를 부모에게 전파합니다. 브로드 캐스트 -이벤트를 어린이에게 전파합니다. $ on-$ emit 및 $ broadcast에 의해 전파되는 이벤트를 청취하는 방법.

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>

app.js 예제 :

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

여기에 코드를 테스트 할 수 있습니다 : http://jsfiddle.net/zp6v0rut/41/


2

아래 코드는 이벤트가 상위 컨트롤러 (rootScope)로 전달되는 두 개의 하위 컨트롤러를 보여줍니다.

<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 이벤트 문서에 따르면 수신 측에는 다음과 같은 구조의 인수가 포함되어야합니다

@params

-이벤트에 대한 정보를 포함하는 이벤트 객체 인 {Object} 이벤트

-수신자가 전달한 {Object} args

$scope.$on('fooEvent', function (event, args) { console.log(args) }); 코드에서

또한 다른 컨트롤러에서 공유 할 수있는 정보를 얻으려는 경우이를 달성 할 수있는 또 다른 방법이 있으며 각 서비스입니다. 서비스가 싱글 톤이므로 컨트롤러간에 정보를 저장하고 가져올 수 있습니다. 해당 서비스의 설정 기능, 이러한 기능 노출, 서비스에서 글로벌 변수 작성 및 정보 저장에 사용


0

가장 쉬운 방법 :

HTML

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

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

    </div>

자바 스크립트

    <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>
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.