Контроллеры динамической загрузки и ng-include
В настоящее время у меня есть приложение с боковой панелью, а боковая панель загружает разные html-шаблоны с помощью ng-include
на основе той операции, которую пользователь хочет сделать. Это приложение, связанное с картой, например, если пользователь выбирает кнопку "Добавить ногу", он загрузит шаблон add_leg.html
на боковой панели с помощью ng-include
:
// The Javascript code:
$scope.addLeg = function() {
$scope.sidebar = true;
$scope.sidebar_template = '/partials/legs/add_leg.html';
}
// Simplified example of HTML:
<html>
<div ng-app="MyApp" ng-controller="MainCtrl">
<a ng-click="addLeg()">Add Leg</a>
<a ng-click="addRoute()">Add Route</a>
<a ng-click="editLeg()">Edit Leg</a>
<a ng-click="editRoute()">Edit Route</a>
...
<div id="sidebar" ng-class="{'sidebar-hidden': sidebar == false}">
<div ng-include src="sidebar_template"></div>
</div>
<google-map></google-map>
</div>
Это хорошо, хорошо и работает по своему желанию, но на данный момент мое приложение использует только один контроллер (MainCtrl
in js/controllers.js
), и он начинает становиться действительно загроможденным. Сейчас у меня много методов, потому что функциональность приложений расширяется. Я хотел бы разделить контроллер на несколько контроллеров, сохраняя при этом эту функциональность боковой панели.
Я хочу иметь MainCtrl
в качестве основного контроллера, который контролирует загрузку шаблона боковой панели (путем изменения переменной sidebar_template
, указывающей на место назначения файла), и я хочу, чтобы он контролировал некоторые из связанных с глобальной картой методы (например, выборка заголовков пригородов из координат и т.д.).
Я попытался разбить его так:
controllers/js/main.js - MainCtrl
controllers/js/legs.js - LegCtrl
controllers/js/routes.js - RouteCtrl
Я хочу, чтобы LegCtrl
и RouteCtrl
наследовали MainCtrl
, поэтому я могу получить доступ к его области и методам, и все это прекрасно. Но теперь проблема заключается в том, как я динамически загружаю контроллер в div на боковой панели, исходя из того, какая функциональность требуется. Первоначально все мои методы находились в MainCtrl
, а на обертке div, которая окружает боковую панель div (см. Выше для примера), так что это не проблема.
Например, скажем, я нажимаю кнопку "Добавить ногу", вам нужно вызвать addLeg
в LegCtrl
, но LegCtrl
не загружается в приложение, поэтому у него нет доступа к метод. Я мог бы сохранить addLeg()
внутри MainCtrl
и изменить его sidebar_template
для загрузки шаблона, но ничего в шаблоне не будет работать, потому что теперь он вызывает методы из LegCtrl
.
Мне нужно как-то динамически загрузить контроллер на боковой панели ng-include
div, что-то вроде этого возможно:
// MainCtrl
$scope.addLeg = function() {
$scope.required_controller = LegCtrl;
$scope.sidebar = true;
$scope.sidebar_template = '/partials/legs/add_leg.html';
LegCtrl.addLeg();
}
<div id="sidebar" ng-class="{'sidebar-hidden': sidebar == false}">
<div ng-include src="sidebar_template" ng-controller="{{required_controller}}"></div>
</div>
В нерабочем примере выше вы можете увидеть возможное решение, о котором я думал, но мне нужно LegCtrl
быть фактической функцией контроллера, а не объектом (для ng-controller
для работы). Мне также нужен способ вызвать addLeg
на LegCtrl
из MainCtrl.addLeg
(возможно, используя широковещание?).
Если кто-то может указать мне в правильном направлении, это было бы здорово. Извините за огромный пост, ему нужно было немного объяснить, чтобы сделать его связным. Надеюсь, это имеет смысл. Спасибо.
Обновление: Я думаю, что нашел решение, использующее службу, чтобы действовать как элемент управления навигацией (он загрузит соответствующие шаблоны и передаст событие новому динамику, который будет динамически загружен, чтобы сообщить об этом какую функцию выполнить):
http://plnkr.co/edit/Tjyn1OiVvToNntPBoH58?p=preview
Просто пытаюсь проверить эту идею сейчас, но трансляция .on
не работает. Я думаю, это потому, что трансляция срабатывает до загрузки шаблона. Как я могу это исправить? Является ли это хорошим решением для того, что я делаю?
Ответы
Ответ 1
Если я правильно понял, что вы можете попробовать, было бы создать представление шаблона специально для создания новой ноги.
От главного контроллера реализуется некоторая логика, чтобы показать шаблон
$scope.addLeg=function() {
$scope.showAddLeg=true;
}
В представлении шаблона AddLeg будет загружаться контроллер и, следовательно, создать механизм для добавления нового нога. Шаблон будет выглядеть как
<script type="text/ng-template" class="template" id="addLegTemplate">
<div ng-controller='LegsController'>
<!--html for adding a new leg-->
</div>
</script>
Вы можете включить этот шаблон в свой основной html, используя ng-if + ng-include.
<div ng-if='showAddLeg'><div ng-include='addLegTemplate'/></div>
В принципе, вы можете создать несколько представлений и привязать их к одному контроллеру (но экземпляр будет отличаться). В этом случае LegsController
может быть привязан к нескольким представлениям для поддержки полной функциональности.
Ответ 2
Мне нравится этот сценарий, управляемый данными, просто манипулируйте строками в шаблонах:
$scope.templates = [
{ name: 'include1.html', url: 'partials/include1.html' }
];
$scope.addTemplate = function(name, url) {
$scope.templates.push({ name: name, url: url });
};
и разметка:
<div ng-repeat="template in templates" ng-include="template.url"></div>
Чтобы добавить или удалить виды, просто измените шаблоны et voila! Если вам нужно больше кода контроллера, вы можете включить ссылку на script в include. Я предполагаю, что могут быть сложности с привязкой к данным в частичном представлении, но компиляция $должна их разрешать.
Ответ 3
Я расколол вашу демонстрацию plunkr в ту, которая, как я считаю, делает то, что вы ищете: http://plnkr.co/edit/whsjBT?p=preview
Это показывает, что событие передается от одного контроллера к другому ПОСЛЕ 2-го контроллера (LegCtrl
в нашем примере здесь) загружается через ng-include
и передает его.
Я использовал событие $includeContentLoaded
из ng-include
, чтобы отложить трансляцию события до тех пор, пока angular не сообщит, что загружается add_leg.html
. Также я думаю, что были некоторые проблемы с тем, как вы использовали $broadcast()
... первый параметр должен быть таким же, как тот, который использовался в $on()
в LegCtrl
Еще одна идея, которую нужно рассмотреть, - просто использовать ваш сервис Navigation
для совместного использования состояния между контроллерами, если это необходимо в вашем сценарии.