Take the 2-minute tour ×

At the moment I have an app that has a sidebar, and the sidebar loads different html templates using ng-include based off what operation the user chooses to do. It's a map related app, so for example, of the user selects the Add Leg button it will load the add_leg.html template into the sidebar using ng-include:

// The Javascript code:
$scope.addLeg = function() {
    $scope.sidebar = true;
    $scope.sidebar_template = '/partials/legs/add_leg.html';    

// Simplified example of 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>


This is all well and good and works as desired, but at the moment my app is only using one controller (MainCtrl in js/controllers.js) and it's starting to get really cluttered. I've got a lot of methods now because the apps functionality is expanding. I'd like to split my controller up into multiple controllers whilst retaining this sidebar functionality.

I want to have MainCtrl as the main controller that controls the loading of the sidebar template (by changing the sidebar_template variable that points to the file destination), and I want it to control some of the global map related methods (like fetching suburb names from coordinates etc).

I've tried to split it like so:

controllers/js/main.js - MainCtrl
controllers/js/legs.js - LegCtrl
controllers/js/routes.js - RouteCtrl

I want the LegCtrl and RouteCtrl to inherit the MainCtrl so I can access its scope and methods, that's all fine. But now the problem is how do I dynamically load the controller onto the sidebar div based off what functionality is required. Originally all of my methods were in MainCtrl, and that's on the wrapper div that surrounds the sidebar div (see above again for an example), so it wasn't a problem.

For example, say I press the 'Add Leg' button, it's going to need to call addLeg in LegCtrl, but LegCtrl isn't loaded on the app, so it doesn't have access to the method. I could keep addLeg() inside the MainCtrl, and have it change the sidebar_template variable to load the template, but nothing in the template will work because it is calling methods from inside the LegCtrl now.

I need to somehow dynamically load the controller on the sidebar's ng-include div, something like this perhaps:

// MainCtrl
$scope.addLeg = function() {
    $scope.required_controller = LegCtrl;

    $scope.sidebar = true;
    $scope.sidebar_template = '/partials/legs/add_leg.html';    


    <div ng-include src="sidebar_template" ng-controller="{{required_controller}}"></div>

In the non-working example above you can see a possible solution I've thought of, but I need LegCtrl to be the actual controller function, not an object (for ng-controller to work). I also need some way to call addLeg on the LegCtrl from the MainCtrl addLeg (perhaps using broadcast?).

If anyone can point me in the right direction that'd be great. Sorry for the huge post, it needed a bit of explaining to make it coherent. Hopefully it makes sense. Thanks.

Update: I think I've found a solution using a service to act as the navigation control (it will load the relevant templates and broadcast an event to the new controller being dynamically loaded to tell it what function to execute):


Just trying to test this idea out now, but the broadcast .on doesn't work. I think it's because the broadcast fires before the template loads. How can I fix this? Is this a good solution for what I'm doing?

share|improve this question
I saw your plunker and have edited it to include to console messages. It will show you that event is published first and then listener starts listening. This happens because every thing is lazy loaded in angular app. plnkr.co/edit/rWZ3x2Jzk9EV3OpD1HF1?p=preview –  Rishabh Singhal Jul 29 '13 at 1:21
add comment

2 Answers

up vote 5 down vote accepted

If i have understood you correctly what you can try would be to

Create a template view specifically to create a new leg.

From the main controller implement some logic too show the template

$scope.addLeg=function() {

The AddLeg template view would load the controller and hence provide a mechanism to actually add new leg. The template would look like

<script type="text/ng-template" class="template" id="addLegTemplate">
    <div ng-controller='LegsController'>
    <!--html for adding a new leg-->

You can include this template inside you main html using ng-if + ng-include.

<div ng-if='showAddLeg'><div ng-include='addLegTemplate'/></div>

Basically you can create multiple view and bind to same controller (but instance would differ). In this case the LegsController can be binded to multiple views to support the complete functionality.

share|improve this answer
The problem with this is if I'm loading new templates related to leg functionality (i.e. maybe on the addLeg template is a button to load the editLeg template), when they switch templates it will have its own controller definition in the new controller (and thus lose scope and all state variables will be lost). –  andro1d Jul 23 '13 at 6:56
You can share model by keeping it outside the controllers and passing it as part of ng-init. –  Chandermani Jul 23 '13 at 8:58
hey Chandermani, can you take a look at my update? Thanks. –  andro1d Jul 25 '13 at 0:23
There are multiple option i see. ng-include can take a onLoad function and there is an event on template loading in ng-include too. Try it. If nothing works you can always broadcast your message within a $timeout function, with a delay. –  Chandermani Jul 25 '13 at 3:27
add comment

I've forked your plunkr demo into one that I believe does what you're looking for: http://plnkr.co/edit/whsjBT?p=preview

This demonstrates an event being broadcast from one controller to another AFTER the 2nd controller (LegCtrl in our example here) is loaded via ng-include and passing it data.

I used $includeContentLoaded event from ng-include to delay broadcasting the event until angular reports that add_leg.html is loaded. Also I think there were some issues with how you were using $broadcast()... it's first parameter should be the same as the one used in $on() in LegCtrl

Another idea to consider is simply using your Navigation service itself to share state between the controllers if that's appropriate in your scenario.

share|improve this answer
add comment

Your Answer


