Gert-Jan Kooijmans Gert-Jan Kooijmans - 1 month ago 27
AngularJS Question

Listen for broadcast event from controller within directive

I have a controller that broadcasts an event when some content is loaded like this

angular.module('myApp')
// Using rootScope now
.controller('SubCtrl', ['$rootScope', '$scope', '$http', function ($rootScope, $scope, $http) {
$http.get('/scripts/data/content.json')
.then(function(response) {
$scope.content = response.data;
$rootScope.$broadcast('dataloaded');
});
}]);


In the matchHeight directive I am listening for the dataloaded event

angular.module('myApp')
.directive('matchHeight', ['$timeout', function ($timeout) {
var linkFunction = function(scope, element, attrs) {
scope.$on('dataloaded', function() {
$timeout(function() {
angular.element(element).matchHeight(attrs);
});
});
};

return {
restrict: 'A',
link: linkFunction
};
}]);


I am using ui-router to manage the states
This is the HTML

<div class="row usps">
<div class="col-sm-4 usp-block" ng-repeat="block in content.marketing" match-height>
// Inner HTML
</div>
</div>


The broadcast event is not picked up from within the directive. What am I doing wrong?

Answer

Because of the fact that you are inside ngRepeat, contents will get rendered only after the broadcast triggers, so directive will. Then your directive link will only subscribe to the event but it won't execute, because it had already been executed before that ngRepeat finishes rendering your directive.

In order to fix this, by the fact that ngRepeat will recreate your list every time you change the array, directive will always be reconstructed when necesssary so you don't have to listen to an event.

angular.module('myApp')
  .directive('matchHeight', ['$timeout', function ($timeout) {
    var linkFunction = function(scope, element, attrs) {
      $timeout(function() {
        angular.element(element).matchHeight(attrs);
      });
  };

  return {
    restrict: 'A',
    link: linkFunction
  };
}]);