Angularjs different controllers for one include

I want to have element where i can have 2 views using their own controller but only one at a time. I can't use a ng-view and use the routeProvider because in the future I need to include more ng-includes that need to change their content depending on the possible actions.

I created a fiddle http://jsfiddle.net/EvHyT/29/.

So I used a ng-include and then I set the src for it from a main controller. At that point I want to use controller 1 or controller 2.

function MainCtrl($rootScope, $scope, navService){
$scope.template = {};

$scope.loadCtrl1=function(param){
    navService.loadCtrl1(param);
}

$scope.loadCtrl2=function(param){
    navService.loadCtrl2(param);
}

$rootScope.$on('loadCtrl1', function(e, args){
    $scope.template = {'url': 'temp1'};
});

$rootScope.$on('loadCtrl2', function(e, args){
     $scope.template = {'url': 'temp2'};       
});
}

I use a service for communication because i want to move the load controller functions in a child controller.

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


myApp.factory('navService', function($rootScope) {
return {
     loadCtrl1:function(param){
        $rootScope.$broadcast('loadCtrl1', {'id':param});   
    },

    loadCtrl2:function(param){
        $rootScope.$broadcast('loadCtrl2', {'id':param});
    }
};
});

I know this solution is bad because the controllers are not yet created when a different template is inserted so my event listener will not fire. Also can I destroy the previous instances of the controller because switching between the two controllers makes my event fire multiple times.

function Child1Ctrl($scope, $rootScope){
 $rootScope.$on('loadCtrl1', function(e, args){
   alert(args.id);
});
}

function Child2Ctrl($scope, $rootScope){

$rootScope.$on('loadCtrl2', function(e, args){
      alert(args.id);
});
}

You don't need to broadcast (and shouldn't be broadcasting) to make this happen. In my experience, if you're broadcasting on the rootScope, you're probably working too hard.

A simpler way of loading the template is very similar to what you're doing:

my.NavService = function() {
  this.template = 'index.html';
  this.param = null;
};
my.NavService.prototype.setTemplate(t, p) {
  this.template = t;
  this.param = p;
};

my.ctrl = function($scope, nav) {
   $scope.nav = nav;
   $scope.load = function(t, p) {
     nav.setTemplate(t, p);
   };
};

my.ctrl1 = function($scope, nav) {
  $scope.param = nav.param;
};

my.ctrl2 = function($scope, nav) {
  $scope.param = nav.param;
};

module.
  service('nav', my.NavService).
  controller('mainCtrl', my.ctrl).
  controller('ctrl1', my.ctrl1).
  controller('ctrl2', my.ctrl2);
<script type="text/ng-template" id="temp1.html">
  <div ng-controller="ctrl1">Foo {{param}}.</div>
</script>
<script type="text/ng-template" id="temp2.html">
  <div ng-controller="ctrl2">Bar {{param}}.</div>
</script>

<div ng-controller="mainCtrl">
  <a ng-click="load('temp1.html', 16)">Load 1</a>
  <a ng-click="load('temp2.html', 32)">Load 2</a>
  <div ng-include src="nav.template"></div>
</div>

A setup like this would work much better for you.

Alternatively, you should look into selectively showing elements with ng-switch. Unlike ng-show/hide, ng-switch does not simply add "display:none" to the CSS. It removes it from the DOM.

Some notes:

  • The above example may not be a working example, it's a demonstration of the idea. A working example can be seen here: http://jsbin.com/ofakes/1 It modifies your original code.
  • JSFiddle had some issues with loading the include from the on page script tag.
  • JSBin was a little better.
  • I didn't really get it to work as expected until I broke out the templates into their own files.