1

I have seen the ability to have a dynamic templateUrl within a Directive in Angular but while researching I have yet to see a dynamic template.

.directive('col', function () {
    var template = '<div class="one" ng-transclude></div>';
    return {
        restrict: 'E',
        scope: {},
        transclude: true,
        replace: true,
        template: template,
        link: function (scope, ele, attrs) {
            if (attrs.two !== undefined) {
                template = '<div class="two" ng-transclude></div>';
            } else if (attrs.three !== undefined) {
                template = '<div class="three" ng-transclude></div>';
            } else {
                template = '<div class="one" ng-transclude></div>';
            }
            console.log(template);
        }
    };
})

HTML:

<col three>Three</col>
<col two>Two</col>
<col>Nothing</col>

The console shows appropriately:

<div class="three" ng-transclude></div>
<div class="two" ng-transclude></div>
<div class="one" ng-transclude></div>

However the output shows the default / initial <div class="one" ng-transclude></div>

2
  • 2
    You probably want to be using the compile feature like this question stackoverflow.com/questions/10629238/… Commented Sep 20, 2013 at 20:16
  • @nuclearghost +1, this is good. Thanks. I will have to keep this in mind for future use. Commented Sep 20, 2013 at 20:43

3 Answers 3

2

This is because the template is collected before the link function is fired, if your only trying to change the classes then just do something like this.

.directive('col', function () {
    var template = '<div class="{{class}}" ng-transclude></div>';
    return {
        restrict: 'E',
        scope: {},
        transclude: true,
        replace: true,
        template: template,
        link: function (scope, ele, attrs) {
            $scope.class = attrs.three ? 'three' : attrs.two ?'two' : attrs.one ? 'one' : '';
        }
    };
});

Other than that I don't know how else you would accomplish it.

Sign up to request clarification or add additional context in comments.

1 Comment

With some minor tweaking this one worked perfectly, thanks. $scope was changed to scope and your ternary operator didn't work properly in my instance, but that could be on me.
0

When you say 'template = 'xxx' in your link function it is referencing your template variable, not the property on the returned object. Try this:

.directive('col', function () {
    var result = {
        restrict: 'E',
        scope: {},
        transclude: true,
        replace: true,
        template: template,
        link: function (scope, ele, attrs) {
            if (attrs.two !== undefined) {
                result.template = '<div class="two" ng-transclude></div>';
            } else if (attrs.three !== undefined) {
                result.template = '<div class="three" ng-transclude></div>';
            } else {
                result.template = '<div class="one" ng-transclude></div>';
            }
            console.log(result.template);
        }
    };
    return result;
})

Comments

0

If the template is dynamically constructed based on the attributes then you can just supply a template function passing in the attributes

.directive('col', function () {
    return {
        restrict: 'E',
        scope: {},
        transclude: true,
        replace: true,
        template: function(element, attrs) {
            var template = null;

            if (attrs.two !== undefined) {
                template = '<div class="two" ng-transclude></div>';
            } else if (attrs.three !== undefined) {
                template = '<div class="three" ng-transclude></div>';
            } else {
                template = '<div class="one" ng-transclude></div>';
            }

            return template;
        },
        link: function (scope, element, attrs) {

        }
    };
})

If the template is dynamically constructed based on the model then it's bit more involved. Note that the transclusion is done explicitly rather than using the ng-transclude directive.

.directive('col', function () {
    return {
        restrict: 'E',
        scope: {
            myVariable: '='
        },
        transclude: true,
        replace: true,
        link: function (scope, element, attrs, nullController, transclude) {
            var template = null;

            if (scope.myVariable == 'two') {
                template = '<div class="two"></div>';
            } else if (scope.myVariable == 'three') {
                template = '<div class="three"></div>';
            } else {
                template = '<div class="one"></div>';
            }

            element.html(template);
            $compile(element.contents())(scope);

            transclude(scope.$parent, function(clone, scope) {
                element.children().append(clone);
            });
        }
    };
})

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.