Search code examples
javascriptangularjsangular-directive

Dynamically insert ng-controller in template as string


I have a custom directive and it's template includes an ng-controller directive which needs to be dynamically set. Here is my non working code....

angular.module('myDirectives').directive('tabPanel', function() {

return {
    restrict: 'E',
    scope: {
        id: '@?tabId',
        template: '@?',
        controller: '@?'
    },
    controller: 'TabPanelCtrl as tabPanelCtrl',
    transclude: true,
    template: getTemplate
};

function getTemplate(element, attr) {

    if(attr.template && attr.controller){
        return '<tab-panel-inner ng-include="template" ng-controller="controller" ng-transclude></tab-panel-inner>'
    }

    else{
        return '<tab-panel-inner ng-transclude></tab-panel-inner>'
    } 

}

function postLink(scope, element, attr, ctrls) {

    var containerCtrl = ctrls[0];

    // Add container controller to scope if it exists.
    if(containerCtrl){
        scope.tabPanelCtrl.containerCtrl = containerCtrl;
    }

    scope.tabPanelCtrl.initialize();

}

});

I use the directive like this:

<tab-panel tab-id="..." template="..." controller="TestTabFoldersCtrl as testTabFolders"></tab-panel>

The error I get is:

Error: [ng:areq] Argument 'controller' is not a function, got string

Now, I know it's a string, but surely when using the ng-controller attribute in normal HTML you provide a string to it?

I have tried changing the template to this:

return '<tab-panel-inner ng-include="template" ng-controller="{{controller}}" ng-transclude></tab-panel-inner>'

I thought the curly braces might make it evaluate it, but it doesn't help. The only thing that works is hard-coding the


Solution

  • You just need to concatenate the attribute values into the template string:

    function getTemplate(element, attr) {
    
        if(attr.template && attr.controller){
            var template ='<tab-panel-inner ng-include="' + attr.template + '"';
                template += ' ng-controller="'+ attr.controller + '" ng-transclude></tab-panel-inner>' 
            return template; 
        }
    
        else{
            return '<tab-panel-inner ng-transclude></tab-panel-inner>'
        } 
    
    }