Как общаться между контроллерами, не используя SharedService между ними?

Я читал все ответы о связи между контроллерами и директивами, но, как мне кажется, произошел с помощью общего сервиса и внедрил его каждому из них. Когда я разрабатываю очень масштабное приложение, я не знаю, что будет на моей странице. У меня может быть 2 контроллера для связи между ними, и у меня также может быть 5 директив и 2 контроллера на одной странице. Я не знаю с нуля, что будет внутри моего представления / страницы, поэтому мне нужен лучший способ, как общаться между ними. Я ищу этот лучший способ сделать это, правильный путь AngularJS.

http://i60.tinypic.com/2z87q05.png

Выше приведен пример моего вида: с левой стороны у меня есть дерево директив, с правой стороны у меня есть контроллер диаграммы и сетка директив. У меня может быть больше, чем это, но это хороший пример того, что я могу иметь. Имейте в виду, что представление может иметь X компонент, вы не знаете с самого начала, что будет в нем.

Теперь, скажем, каждый раз, когда я выбираю узел в дереве слева, я хочу сообщить другим контроллерам, что событие nodeSelectedChange произошло. Я не хочу внедрять в каждый из них сервис, который содержит эту информацию, поэтому я подумал о чем-то вроде наличия контроллера диспетчера страниц, который является отцом всего представления. Все мои контроллеры / директивы на моей странице должны общаться друг с другом только PageManagerController, он единственный, кто знает, что у него внутри.

Здесь важно помнить: дерево не знает, что страница имеет диаграмму или сетку, им не нужно знать друг друга, чтобы общаться. Менеджер страниц знает все, и теперь я хочу, чтобы он сотворил магию - должен ли он иметь сервис? Должен ли каждый компонент иметь сервис, а сервис может общаться с сервисом PageManager?

Помоги мне подумать. Надеюсь, я смогу соединить все точки, чтобы создать ЛУЧШИЙ способ общения. Я думаю, что способ sharedService хорош для небольших приложений, когда вы с самого начала знаете, что происходит в вашем приложении, но большую часть времени - вы просто не знаете, кто и когда собирается использовать вашу директиву, он должен иметь возможность говорить со всеми.

Что мне не нравится в событиях:

  1. События запускаются внутри контроллера, в то время как он должен быть внутри службы.
  2. Контроллер слушателя должен знать имя события, которое он собирается прослушать. Если я изменю имя события на $ emit или $ broadcast, мне нужно пройтись по всем слушателям $on("eventName") во всех приложениях и изменить это уникальное имя.
  3. Директива похожа на черный ящик, я не хочу каждый раз проверять внутри него и находить названия событий, которые он передает, чтобы общаться с ним.

Мне нужен способ выставить события NAMES вне директивы, возможно, с помощью службы, подключенной к этому контроллеру.

3 ответа

Решение

Это действительно зависит от типа информации, которую вы хотите передать из директивы дерева в другие разделы страницы.

Перед вами есть несколько вариантов:

Используйте область действия

Как уже упоминалось выше, вы можете запустить событие и прослушивать события в различных контроллерах и / или сервисах. Тем не менее, это может стать очень уродливым, очень быстрым. Отслеживание событий и выяснение того, какие слушатели событий активны в данный момент, могут дать лучшим инженерам мигрень!

Используйте Сервис

Другой вариант - использовать Сервис, скажем, PageManagerService. В таком случае,

  • Каждый щелчок элемента дерева устанавливает некоторую информацию о PageManagerService, говоря, какую страницу, какие объекты и какие элементы нужно отображать.
  • Каждый компонент, который нужно изменить, может
    • Зарегистрируйте прослушиватель, который будет запускаться при изменении PageManagerService
    • Добавьте часы в службу и запустите ее код, когда PageManagerService изменится.

Сам сервис будет просто находиться в общем состоянии, и это будет зависеть от директив и компонентов о том, как он хочет потреблять и реагировать на изменения в состоянии.

Используйте UI Router

Но чем больше я об этом думаю, тем больше это похоже на хороший пример использования чего-то вроде UI Router. UI Router позволяет вам определять состояния, и разные части страницы по-разному реагируют на изменения состояния. Каждый раздел может реагировать на изменение состояния по-своему, загружая

  • Другой контроллер
  • Другой шаблон, возможно, с другими компонентами и виджетами

Так что у вас в конечном итоге есть структура с

  • Директива о дереве слева
  • UI-представление с именем, скажем, top
  • Пользовательский интерфейс с именем, скажем, снизу

Каждый элемент в вашей директиве дерева может тогда быть ui-sref, который является просто причудливым способом сказать вместо перенаправления на URL, перенаправления в состояние.

Затем вы можете определить свои конфигурации в приложении в одном месте, например:

$stateProvider.state('dashboard', {
  views: {
    "top": { templateUrl: 'my/dashboard.html', controller: 'DashboardCtrl'}
    "bottom": { templateUrl: 'my/dashboard-grid.html', controller: 'DashboardGridCtrl'}
  }
})

Точно так же вы можете иметь определение состояния для каждого элемента в вашей директиве дерева, и каждый из них будет просто ссылкой на другое состояние.

Конечно, определения состояний выполняются в разделе конфигурации в приложении AngularJS, о котором вы должны знать до его запуска. Что если вам нужны динамические состояния?

Ну, несколько ответов / мыслей, которые помогут вам в этом:

  • Контроллеры и сервисы должны быть предопределены, вы не будете динамически создавать HTML-контент и / или JS-контроллеры.
  • Можно представить $ stateProvider как глобальную переменную в разделе конфигурации и динамически вызывать stateProvider.state внутри контроллера / службы, где бы у вас не были новые определения состояний.
  • Чаще всего контроллеры и HTML остаются постоянными, и нам просто нужно запускать различные состояния с различными параметрами. Это легко сделать, вызвав функцию transitionTo для перехода в определенное состояние с различными параметрами состояния.

Есть несколько хороших практик:

  1. Использовать $scope взаимодействовать между директивами и контроллерами для зависимостей во время выполнения (например, модели, которые вы выбираете с сервера, экземпляры классов и т. д.). Для этого необходимо иметь изолированную область с атрибутами, сопоставленными с зависимостями:

    directive('tree', function(){
      return {
        scope: {
          somevalue : "="
        }
      }
    });
    

    Используйте это так:

    <tree somevalue="objectFromController">
    
  2. Используйте внедренные сервисы для взаимодействия со статическими зависимостями ( модели презентаций, глобальное разделяемое состояние и т. Д.)

    directive('tree', function(treeState){
      return {
        scope: {
          somevalue : "="
        },
        link: function(scope){
          // some logic updating the treeState
          treeState.openNodes = ['x', 'y'];
        }
      }
    });
    
    controller('ctrl', function($scope, treeState){
      // react to treeState changes
      // you can use $scope.$watch for it
      // or any other way you like
      // see: https://github.com/mr-mig/angular-react-to
    
    });
    
  3. Если вы хотите добиться максимальной компоновки, придерживайтесь первого шаблона:

    directive('tree', function(){
      return {
        scope: {
          model : "="
        },
        link: function(scope){
          // some logic updating the treeState, stored as scope.model
          scope.model.openNodes = ['x', 'y'];
        }
      }
    });
    
    controller('ctrl', function($scope, treeFactory){
      $scope.treeModel = treeFactory.create();
      // react to treeState changes
      // you can use $scope.$watch for it
      // or any other way you like
      // see: https://github.com/mr-mig/angular-react-to
    });
    

    И создайте этот материал, используя шаблон и привязку в качестве коммуникационной шины:

    <tree model="treeModel">
    

Придерживаясь этого шаблона, вы получите:

  1. Нет событий
  2. Четко определенная директива "interface" (атрибуты в изолированной области видимости)
  3. Простота компоновки
  4. Реактивное поведение, основанное на распространении изменений области

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

Пожалуйста, следуйте одному из моих предыдущих постов. У меня есть настройка, как укурить. Вы можете попробовать пример. Angular Js newbie - ссылка в виде контроллера, запускающая другое действие контроллера

$on : setup a event handler
$emit : communicate to parent controllers
$broadcast : communicate to child controllers

Чтобы узнать больше посетите - https://docs.angularjs.org/api/ng/type/$ rootScope.Scope

Другие вопросы по тегам