Как использовать $broadcast с компонентами?

У меня есть приложение angular 1.x, использующее компоненты, и я хотел бы иметь возможность транслировать сообщения во всех своих компонентах. Контекст следующий: у меня есть служба, которая получает сообщения веб-сокета, и я хочу транслировать их на все мои контроллеры компонентов.

Я думал о $broadcast, но из того, что я нашел здесь нужны $scope и $rootScope. Что несовместимо с использованием компонента, поскольку в моем приложении больше нет $scope.

Есть ли чистый способ сделать это при использовании угловых компонентов?


person Moussa    schedule 23.06.2017    source источник
comment
ваше понимание того, как работает angular, и, следовательно, этот вопрос, слегка ошибочны. При использовании компонентов и/или контроллера в качестве вы по-прежнему используете $scope, даже если не ссылаетесь на него явно.. Вполне допустимо ссылаться на $scope, чтобы получить доступ к $broadcast, не нарушая шаблон компонента.   -  person Claies    schedule 23.06.2017


Ответы (3)


Я бы посоветовал не использовать $braudcast для такого сценария.

Вместо этого создайте простой сервис, который позволит вашим компонентам подписываться на сообщения с помощью Observables. Вы можете создать эти Observables с помощью Rxjs или свернуть свои собственные, используя шаблон субъекта/наблюдателя GoF.

Эта служба будет обновлять наблюдаемые, когда WebSocket получает определенное сообщение.

Еще лучше, взгляните на реализацию Rxjs WebSocket.

person Martin    schedule 23.06.2017

Создание службы вещания, вероятно, самый чистый способ. Если компоненты не находятся в отдельных модулях приложения angular. Вот базовая простая реализация:

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

app.controller('MainCtrl', function($scope, BroadcastService) {
  this.broadcast = BroadcastService;
});
app.component("listenerComponent", {
  template: "<h2>Listener Component</h2><section>{{ $ctrl.message }}</section>",
  controller: function($scope, BroadcastService) {
    $scope.broadcast = BroadcastService;
    this.message = $scope.broadcast.message;
    $scope.$watch('broadcast.message', function(newVal) {
      this.message = newVal;
    }.bind(this))
  }
});

app.component("broadcastComponent", {
  template: '<h2>Broadcast Component</h2><form ng-submit="$ctrl.broadcast()"><input type="text" ng-model="$ctrl.newMessage"><button>Broadcast</button></section>',
  controller: function($scope, AppService) {
    this.newMessage = '';
    this.broadcast = function() {
      AppService.post(this.newMessage);
      this.newMessage = '';
    }
  }
});

app.factory("BroadcastService", function() {

  return {
    message: 'Default Message',
    post: function(message) {
      this.message = message;
    }
  }

})

app.factory("AppService", function(BroadcastService) {
  return {
    post: function(message) {
      BroadcastService.post("AppService Post Successful!!!" + message);
    }
  }

})
<!DOCTYPE html>
<html ng-app="myApp">

  <head>
    <meta charset="utf-8" />
    <title>Broadcast App</title>
    <script>document.write('<base href="' + document.location + '" />');</script>
    <link rel="stylesheet" href="style.css" />
    <script data-require="[email protected]" src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.11/angular.min.js" data-semver="1.5.11"></script>
    <script src="app.js"></script>
  </head>

  <body ng-controller="MainCtrl as vm">
    <h1>Broadcast Message:</h1> {{vm.broadcast.message }}

    
    <listener-component></listener-component>
    <broadcast-component></broadcast-component>
  </body>

</html>

person Hoyen    schedule 23.06.2017

Как указано в комментарии Claies, вполне возможно просто использовать $scope, сохраняя шаблон компонента. Вы можете внедрить контроллер компонентов вместе с ним и $broadcast, $emit, $on как обычно.

// parentController
controller: function ($scope) {
    $scope.$broadcast('someevent', someargs);
}

// childController
controller: function ($scope) {
    $scope.$on('someevent', function (event, args) {
        // function implementation...
    });
person Sotem    schedule 03.05.2019