Search code examples
javascriptangularjsangular-components

How to listen for an event in AngularJS component?


In AngularJS we can broadcast, and listen for events:

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

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

Is there any way to listen for events inside a component?

What I want to achieve is to execute some action on set of components which are repeated inside a form. Ng-repeat iterates over some model of course. Some data from the model is bound to the component. It's easy to bind function to component, so component can execute some logic, but the opposite direction doesn't seem to be so easy.

<div ng-repeat="someObject in mainModel.listOfObjects">
   <someControl ng-model="someObject.foo"></someControl>
   <custom-component ng-model="someObject.bar"></custom-component>
</div>
<someButton ng-click="executeActionOnAllCustomComponents()">

Solution

  • I think your best bet is keep using the standard event emitting with $emit() and $broadcast(). angular 1.5 introduced some new hooks and sintax but inside a component you can always inject $rootScope and $scope, and handling any event as you were used to in angular < 1.5.

    Template:

    <div ng-controller="parentController">
     <div ng-repeat="someObject in mainModel.listOfObjects">
       <someControl ng-model="someObject.foo"></someControl>
       <custom-component ng-model="someObject.bar"></custom-component>
     </div>
    </div>
    

    Parent controller:

    angular.controller('parentController', ['$scope', function($scope){
     ..
     if(somethingHappend)
       $scope.$broadcast('event.sample', {}); //down in the scope chain
    })
    

    Component:

    angular.component('customComponent', {
     bindings: {
      ngModel: '<' //one-way binding
     },
     controller: MyCtrl
    }
    MyCtrl.$inject = ['$scope', '$rootScope'];
    
    function MyCtrl('$scope', $rootScope){
     ..
     $scope.$on('event.sample', function(evt, data){
      //do your logic
     }
    
    
    }
    

    Another option, if you want to check for changes on your model (made from the othe parent scope, supposing a one-way binding on your scope variables), is to use the hook $doCheck which is triggered each digest cycle, as opposed to the old watch mechanism you must save your old value and compare it to the new one.

    var self = this;
    var oldModel = angular.copy(self.ngModel);
    self.$doCheck = function(){
     if(self.model !== oldModel){
       //do something
     }
    }