O que faz $broadcast ser diferente de $emit em Angular.js?

January 7, 2017

Ambas são funções bem conhecidas por pessoas por pessoas que usam Angular.js com uma certa frequência, porém, agem de uma maneira um pouco diferente. Tanto $broadcast quanto $emit são funções que disparam eventos para escopos definidos em outras entidades.

A diferença está em como cada uma delas funciona. Quando usamos $emit para propagar um evento, todos os escopos acima do escopo em que o evento foi disparado recebem o alerta, incluindo $rootScope. Quando usamos $broadcast, todos os escopos abaixo do escopo em que o evento foi disparado recebem o alerta.

Vamos observar melhor com um exemplo de código. Suponha que tenhamos a seguinte estrutura de controllers.


<div ng-app="foobar">
  <div ng-controller="MainCtrl as main">
    {{ main.msgFromSecondCtrl }}
    <div ng-controller="FirstCtrl as first">
      {{ first.data }}
      {{ first.msgFromSecondCtrl }}
      <div ng-controller="SecondCtrl as second">
        {{ second.data }}
      </div>
      <div ng-controller="ThirdCtrl as third">
        {{ third.data }}
      </div>
    </div>

    <div ng-controller="FourthCtrl as fourth">
      {{ fourth.data }}
      {{ fourth.msgFromSecondCtrl }}
      <!-- emit do segundo controller nao chega aqui -->
    </div>
  </div>
</div>

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

app.controller('MainCtrl', MainCtrl);
MainCtrl.$inject = ['$scope'];

function MainCtrl($scope) {
  var vm = this;
  $scope.$on('msgFromSecondCtrl', function(event, data) {
    vm.msgFromSecondCtrl = data;
  });
  $scope.broadcastMainMsg = function() {
    $scope.$broadcast('mainCtrlMsg', [1, 2, 3, 4]);
  };
}

app.controller('FirstCtrl', FirstCtrl);
FirstCtrl.$inject = ['$scope'];

function FirstCtrl($scope) {
  var vm = this;
  $scope.$on('mainCtrlMsg', function(event, data) {
    vm.data = data[0];
  });
  $scope.$on('msgFromSecondCtrl', function(event, data) {
    vm.msgFromSecondCtrl = data;
  });
}

app.controller('SecondCtrl', SecondCtrl);
SecondCtrl.$inject = ['$scope'];

function SecondCtrl($scope) {
  var vm = this;
  $scope.$emit('msgFromSecondCtrl', 'emit do segundo controller');
  $scope.$on('mainCtrlMsg', function(event, data) {
    vm.data = data[1];
  });
}

app.controller('ThirdCtrl', ThirdCtrl);
ThirdCtrl.$inject = ['$scope'];

function ThirdCtrl($scope) {
  var vm = this;
  $scope.$on('mainCtrlMsg', function(event, data) {
    vm.data = data[2];
  });
}

app.controller('FourthCtrl', FourthCtrl);
FourthCtrl.$inject = ['$scope'];

function FourthCtrl($scope) {
  var vm = this;
  $scope.$on('mainCtrlMsg', function(event, data) {
    vm.data = data[3];
  });
  $scope.$on('msgFromSecondCtrl', function(event, data) {
    vm.msgFromSecondCtrl = data;
  });
}

De forma bastante resumida, $emit envia uma mensagem para escopos superiores até chegar em $rootScope, $broadcast envia uma mensagem para todos os escopos inferiores.

Pela estrutura das tags html acima, a gente consegue perceber que quem deveria receber a mensagem msgFromSecondCtrl vinda de SecondCtrl são os controllers que estão acima deste, FirstCtrl e MainCtrl. Controllers que estão no mesmo nível ou num nível abaixo não recebem a mensagem.

Enquanto MainCtrl dispara, com $broadcast, um evento em conjunto com um array contendo quatro elementos. Todos os controllers num nível abaixo devem receber o evento ao registrar um listener como $on.

Comentários

comments powered by Disqus