Как общаться между контроллерами, не используя SharedService между ними?
Я читал все ответы о связи между контроллерами и директивами, но, как мне кажется, произошел с помощью общего сервиса и внедрил его каждому из них. Когда я разрабатываю очень масштабное приложение, я не знаю, что будет на моей странице. У меня может быть 2 контроллера для связи между ними, и у меня также может быть 5 директив и 2 контроллера на одной странице. Я не знаю с нуля, что будет внутри моего представления / страницы, поэтому мне нужен лучший способ, как общаться между ними. Я ищу этот лучший способ сделать это, правильный путь AngularJS.
http://i60.tinypic.com/2z87q05.png
Выше приведен пример моего вида: с левой стороны у меня есть дерево директив, с правой стороны у меня есть контроллер диаграммы и сетка директив. У меня может быть больше, чем это, но это хороший пример того, что я могу иметь. Имейте в виду, что представление может иметь X компонент, вы не знаете с самого начала, что будет в нем.
Теперь, скажем, каждый раз, когда я выбираю узел в дереве слева, я хочу сообщить другим контроллерам, что событие nodeSelectedChange произошло. Я не хочу внедрять в каждый из них сервис, который содержит эту информацию, поэтому я подумал о чем-то вроде наличия контроллера диспетчера страниц, который является отцом всего представления. Все мои контроллеры / директивы на моей странице должны общаться друг с другом только PageManagerController, он единственный, кто знает, что у него внутри.
Здесь важно помнить: дерево не знает, что страница имеет диаграмму или сетку, им не нужно знать друг друга, чтобы общаться. Менеджер страниц знает все, и теперь я хочу, чтобы он сотворил магию - должен ли он иметь сервис? Должен ли каждый компонент иметь сервис, а сервис может общаться с сервисом PageManager?
Помоги мне подумать. Надеюсь, я смогу соединить все точки, чтобы создать ЛУЧШИЙ способ общения. Я думаю, что способ sharedService хорош для небольших приложений, когда вы с самого начала знаете, что происходит в вашем приложении, но большую часть времени - вы просто не знаете, кто и когда собирается использовать вашу директиву, он должен иметь возможность говорить со всеми.
Что мне не нравится в событиях:
- События запускаются внутри контроллера, в то время как он должен быть внутри службы.
- Контроллер слушателя должен знать имя события, которое он собирается прослушать. Если я изменю имя события на $ emit или $ broadcast, мне нужно пройтись по всем слушателям $on("eventName") во всех приложениях и изменить это уникальное имя.
- Директива похожа на черный ящик, я не хочу каждый раз проверять внутри него и находить названия событий, которые он передает, чтобы общаться с ним.
Мне нужен способ выставить события 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 для перехода в определенное состояние с различными параметрами состояния.
Есть несколько хороших практик:
Использовать
$scope
взаимодействовать между директивами и контроллерами для зависимостей во время выполнения (например, модели, которые вы выбираете с сервера, экземпляры классов и т. д.). Для этого необходимо иметь изолированную область с атрибутами, сопоставленными с зависимостями:directive('tree', function(){ return { scope: { somevalue : "=" } } });
Используйте это так:
<tree somevalue="objectFromController">
Используйте внедренные сервисы для взаимодействия со статическими зависимостями ( модели презентаций, глобальное разделяемое состояние и т. Д.)
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 });
Если вы хотите добиться максимальной компоновки, придерживайтесь первого шаблона:
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">
Придерживаясь этого шаблона, вы получите:
- Нет событий
- Четко определенная директива "interface" (атрибуты в изолированной области видимости)
- Простота компоновки
- Реактивное поведение, основанное на распространении изменений области
Вы можете использовать $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