CodesLikeA_Mokey CodesLikeA_Mokey - 7 months ago 26
Javascript Question

Transclude compile time

According to the angular developers guide:

transclude - compile the content of the element and make it available to the directive.

Is it possible to change when the content gets compiled? For performance reasons, I would like to pass the content to a directive which I want to be compiled with the correct scope (parent) but only when/if a certain event takes place. Is that possible? If not, is there a way I can do this going about it differently?

Answer

Just in case others have the same question as I do, I have included a dumbed-down version of what I did. This directive is an expandable/collapsible section that contains transcluded content. For performance reasons, it does not compile the transcluded content until it is needed which, in this case, is only when the section is expanded for the first time. After it is expanded, the content becomes part of the DOM and never needs to be compiled/transcluded again. Most of this directive should be pretty basic and self explanitory, but the controller attribute was something that I have not used in the past.

You will also notice that I have not used the compile or link attributes. For this basic directive, I don't need to do any DOM manipulation when the directive itself is compiled so sticking everything in the controller is just fine. Just to clarify, the order things get run in the directive is Compile, Link, then whatever is in the Controller. The controller gives you access to everything that you can use in the compile/link functions so I put everything there for simplicity, readability, and maintainability.

I hope this helps other noobs like myself. Happy to hear your comments.

uiComponentsModule.directive('CollapsibleSection', ['$timeout', function($timeout) {
    return {
        restrict: 'A',
        replace: true,
        transclude: true,
        scope: {
            sectionTitle:'@',
            sectionId:'@',
            startExpanded:'@'
        },
        template:   '<div>' +
                        '<div ng-click="toggle()" class="collapsible-section-header">' +
                            '<span class="collapsible-section-title"</span>' +
                        '</div>' +
                        '<div class="collapsible-section" ng-show="isExpanded">'+
                            '<div class="transclude-me"></div>'+
                            '<div class="div-clear"></div>'+
                        '</div>' +                      
                    '</div>',
        controller: ['$scope', '$element', '$attrs', '$transclude', function (scope, element, attrs, $transclude) {
            scope.isExpanded = false;
            scope.isLoaded = false;
            scope.toggle = function(){
                if(scope.isExpanded)
                    scope.close();
                else
                {
                    scope.open();
                }
            };

            scope.showTransclude = function(){
                $transclude(function(clone) {
                    element.find(".transclude-me").append(clone);
                });
            };

            scope.open = function(){
                scope.isExpanded = true;
                if(!scope.isLoaded)
                {
                    scope.showTransclude();
                    scope.isLoaded = true;
                }
            };

            scope.close = function(){
                scope.isExpanded = false;
            };
        }]
    }
}
Comments