stealz
stealz

Reputation: 564

How to make directive use the controller specified in directive attribute?

So I have a directive:

<directive data="user" templateUrl="./user.html" controller="UserController"></directive>

I want that directive to use the controller specified in "controller" attribute, as you see above.

Is it possible with AngularJS directives? Or should I do it other way, maybe with components?

My code currently looks like this:

app.directive('directive', function() {
        
        var controllerName = "UserController"; // i want that to dynamicaly come from attribute
        
        // check if controller extists:
        var services = [];
        app['_invokeQueue'].forEach(function(value){ 
            services[value[2][0]] = true;
        });         
        if (!services[controllerName]) controllerName = false;
        
        return {
            
            scope: { 'data' : '=' },

            link: function (scope) {
                
                Object.assign(scope, scope.data);
            },
            
            templateUrl: function(element, attr) {
                
                return attr.templateurl;
            },
            
            controller: controllerName
            
        }
        
    });

Upvotes: 0

Views: 85

Answers (2)

stealz
stealz

Reputation: 564

Okay, so after analysing Petr's answer I post the working code using nested divs:

app.directive('directive', function() {
        
        return {
            scope: { 'data' : '=' },
            
            link: function (scope) {
                
                // this makes your fields available as {{name}} instead of {{user.name}}:
                Object.assign(scope, scope.data);
                
            },
            
            template: function(element, attrs) {
                
                var controllerName = attrs.controller;
                var controllerString = controllerName + ' as vm';
                
                // check if controller extists:
                var services = [];
                app['_invokeQueue'].forEach(function(value){ 
                    services[value[2][0]] = true;
                })
                
                if (!services[controllerName]) {
                    
                    return '<div ng-include="\'' + attrs.templateurl + '\'"></div>'; 
                    
                } else {
                    
                    return '<div ng-controller="' + controllerString + '"><div ng-include="\'' + attrs.templateurl + '\'"></div></div>';
                        
                }
            }
        }
        
    });

Upvotes: 0

Petr Averyanov
Petr Averyanov

Reputation: 9476

You can do following (not exactly what you ask - it creates bunch of nested scopes, but should be sufficient):

    .directive('directive', () => {
        scope: { 'data' : '=' },
        template: (elem, attrs) => {
          return '<div ng-controller="' + attrs.controller + ' as vm"><div ng-include="' + attrs.template + '"></div></div>';
        }
    });

<directive data="user" templateUrl="./user.html" controller="UserController"></directive>
  • you may use $templateCache directly instead of ng-include
  • if you need controller/template/... to be dynamic, you need to observe/watch + dom manipulation + recompile stuff

Upvotes: 2

Related Questions