How to set the dynamic controller for directives?
Solution 1
Now it is possible with AngularJS. In directive you just add two new property called
controller
, name
property and also isolate scope
is exactly needed here.
Important to note in directive
scope:{}, //isolate scope
controller : "@", // @ symbol
name:"controllerName", // controller names property points to controller.
Working Demo for Setting Dynamic controller for Directives
HTML Markup :
<communicator controller-name="PhoneCtrl" ></communicator>
<communicator controller-name="LandlineCtrl" ></communicator>
Angular Controller and Directive :
var app = angular.module('myApp',[]).
directive('communicator', function(){
return {
restrict : 'E',
scope:{},
controller : "@",
name:"controllerName",
template:"<input type='text' ng-model='message'/><input type='button' value='Send Message' ng-click='sendMsg()'><br/>"
}
}).
controller("PhoneCtrl",function($scope){
$scope.sendMsg = function(){
alert( $scope.message + " : sending message via Phone Ctrl");
}
}).
controller("LandlineCtrl",function($scope){
$scope.sendMsg = function(){
alert( $scope.message + " : sending message via Land Line Ctrl ");
}
})
Your case you can try this below code snippets.
HTML Markup :
<div add-icons controller-name="IconsOneCtrl">
</div>
<div add-icons controller-name="IconsTwoCtrl">
</div>
Angular Code :
angular.module('myApp',[]).
directive('addIcons', function(){
return {
restrict : 'A',
scope:{},
controller : "@",
name:"controllerName",
template:'<input type="button" value="(+) plus" ng-click="add()">'
}
}).
controller("IconsOneCtrl",function($scope){
$scope.add = function(){
alert("IconsOne add ");
}
}).
controller("IconsTwoCtrl",function($scope){
$scope.add = function(){
alert("IconsTwo add ");
}
});
Solution 2
This is how it is done:
Inside your directive element all you need is an attribute which gives you access to the name of the controller: in my case my card attribute holds a card object which has a name property. In the directive you set the isolate scope to:
scope: { card: '=' }
This isolates and interpolates the card object to the directive scope. You then set the directive template to:
template: ''
,
this looks to the directive's controller for a function named getTemplateUrl
and allows you to set the templateUrl
dynamically as well. In the directive controller the getTemplateUrl
function looks like this:
controller: ['$scope', '$attrs', function ($scope, $attrs) {
$scope.getTemplateUrl = function () { return '/View/Card?cardName=' +
$scope.card.name; }; }],
I have an mvc controller which links up the proper .cshtml file and handles security when this route is hit, but this would work with a regular angular route as well. In the .cshtml/html file you set up your dynamic controller by simply putting as the root element. The controller will differ for each template. This creates a hierarchy of controllers which allows you to apply additional logic to all cards in general, and then specific logic to each individual card. I still have to figure out how I'm going to handle my services but this approach allows you to create a dynamic templateUrl and dynamic controller for a directive using an ng-repeat based on the controller name alone. It is a very clean way of accomplishing this functionality and it is all self-contained.
Comments
-
kuitos.lau over 3 years
Talk is cheap, show my codes first:
HTML:
<div add-icons="IconsCtrl"> </div>
directive:
angular.module('attrDirective',[]).directive('addIcons', function($compile){ return { restrict : 'A', controller : "IconsCtrl" }, link : function (scope, elem , attrs, ctrl) { var parentElem = $(elem); var icons = $compile("<i class='icon-plus' ng-click='add()'></i>)(scope); parentElem.find(".accordion-heading").append(icons); }, }
});
controller:
function IconsCtrl($scope){ $scope.add = function(){ console.log("add"); }; }
now it works, when i click the plus icon, browser console output "add".
but i want to set the controller into the directive dynamically,like this:
HTML:
<div add-icons="IconsOneCtrl"> </div> <div add-icons="IconsTwoCtrl"> </div>
Controller:
function IconsOneCtrl($scope){ $scope.add = function(){ console.log("IconsOne add"); }; } function IconsTwoCtrl($scope){ $scope.add = function(){ console.log("IconsTwo add"); } }
directive likes :
angular.module('attrDirective',[]).directive('addIcons', function($compile){ return { restrict : 'A', controller : dynamic set,depends on attrs.addIcons }, link : function (scope, elem , attrs, ctrl) { var parentElem = $(elem); var icons = $compile("<i class='icon-plus' ng-click='add()'></i>)(scope); parentElem.find(".accordion-heading").append(icons); }, } });
how to achieve my goal? thanks for your answer!
-
ThePuzzleMaster about 10 yearsThanks for the thorough answer. This worked great for me, although I had to remove the isolate scope from my directive. Otherwise, worked great!
-
james over 9 yearsI'm not sure the isolate scope is necessary either, i also have it working without it. Thanks!
-
Wlada over 9 yearsIs is possible in this case to have optional controller? Tried to pass '@?' to directive controller property but it doesn't work. Is there some other way?
-
Dante Regis about 8 yearsHi Raja! Your solution is working here but I don't really understand why... I can't find any documentation on the 'name' property for directives, and it does not seem to work with only the 'controller' property. What does this 'name' thing do?
-
Robert Koritnik over 7 years@DanteRegis
name
is the directive name which is usually provided when callingangular.directive(name, fn)
. By settingcontroller: '@'
we tell the directive to use controller using the value assigned to directive name (as in<div name="ControllerName">
). This functionality is not documented because it's internal feature that Angular uses to implementngController
directive. It's also the only Anglar directive that actually uses this. Without this feature it would be much harder for them to implement it. The good thing is that we can be assured it will stay as part of Angular 1.x. -
Arjun over 4 yearsThis is great, but can i pass a variables to a controller? if yes then how?