Dynamic NG-Controller Name
Solution 1
What you want to do is have another directive run before anything else is called, get the controller name from some model remove the new directive and add the ng-controller
directive, then re-compile the element.
That looks like this:
global.directive('dynamicCtrl', ['$compile', '$parse',function($compile, $parse) {
return {
restrict: 'A',
terminal: true,
priority: 100000,
link: function(scope, elem) {
var name = $parse(elem.attr('dynamic-ctrl'))(scope);
elem.removeAttr('dynamic-ctrl');
elem.attr('ng-controller', name);
$compile(elem)(scope);
}
};
}]);
Then you could use it in your template, like so:
<div dynamic-ctrl="'blankCtrl'">{{tyler}}</div>
with a controller like this:
global.controller('blankCtrl',['$scope',function(tyler){
tyler.tyler = 'tyler';
tyler.tyler = 'chameleon';
}]);
There's probably a way of interpolating the value ($interpolate
) of the dynamic-ctrl
instead of parsing it ($parse
), but I couldn't get it to work for some reason.
Solution 2
I'm using it in ng-repeat, so this is improved code for loops and sub objects:
Template:
<div class="col-xs6 col-sm-5 col-md-4 col-lg-3" ng-repeat="box in boxes">
<div ng-include src="'/assets/js/view/box_campaign.html'" ng-dynamic-controller="box.type"></div>
</div>
Directive:
mainApp.directive('ngDynamicController', ['$compile', '$parse',function($compile, $parse) {
return {
scope: {
name: '=ngDynamicController'
},
restrict: 'A',
terminal: true,
priority: 100000,
link: function(scope, elem, attrs) {
elem.attr('ng-controller', scope.name);
elem.removeAttr('ng-dynamic-controller');
$compile(elem)(scope);
}
};
}]);
Solution 3
Personally the 2 current solutions here didn't work for me, as the name of the controller would not be known when first compiling the element but later on during another digest cycle. Therefore I ended up using:
myapp.directive('dynamicController', ['$controller', function($controller) {
return {
restrict: 'A',
scope: true,
link: function(scope, elem, attrs) {
attrs.$observe('dynamicController', function(name) {
if (name) {
elem.data('$Controller', $controller(name, {
$scope: scope,
$element: elem,
$attrs: attrs
}));
}
});
}
};
}]);
Comments
-
RonSper about 2 years
I want to dynamically specify a controller based on a config that we load. Something like this:
<div ng-controller="{{config.controllerNameString}}> ... </div>
How do I do this in angular? I thought this would be very easy, but I can seem to find a way of doing this.
-
ido niger over 9 yearsadd :if (scope.src) elem.attr('src', "'"+scope.src+"'"); to support ng-include
-
Kevin Beal over 9 yearsYou're including the
$parse
factory but you aren't using it. -
fancoolo almost 9 yearswhat is the place to put: if (scope.src) elem.attr('src', "'"+scope.src+"'"); ?
-
mlhuff12 about 8 yearsThank you. Exactly what I was looking for. In my case I wanted to be passing a $scope variable instead of a string. So I just needed to do dynamic-ctrl="myScopeVariable"
-
Marc over 7 yearsNide solution. However, I suggest a priority of 550 instead of 100000. This way, the directive is executed before ng-controller (priority 600) but AFTER ng-if (priority 600). Otherwise you controller get initialized (during the call to $compile(elem)(scope)) even if the element is not on the page (if ng-if is false). Also, you can access to element's attributes using 'attrs' parameter of link function to handle camel casing (ie: attrs.dynamicCtrl).