AngularJS compile vs templateUrl

Hello, hello, it has been a while since my last post of ‘given, then, show’. If you are new to here, this is not a recommendation on how to implement, but rather just a show and tell of what you can do.

Given:

– Implement a directive that handles these providers:
– Provider A, B, C, and D share the same template
– Provider A and B have different description
– Provider C and D have no description
– Provider E and F have different templates and different description

Then:

– Assuming that templates and provider descriptions are dumb aka not stored in controllers
– Implement a directive that shows the default template, which is share across the similar providers (A, B, C, D) and a separate template per unique provider E and F.
– Implement a directive just for passing in unique descriptions

————————————>>>>>>————————————
Call the directive

<demo provider="provider"></demo>

Method 1a: use compiler


angular.module('ng-cherie.directives.demo.directive', [])
    .directive('demo', function demoDirective($compile, $templateCache) {
        return {
            bindToController: true,
            controller: 'DemoCtrl as demoCtrl',
            link: function demoLink(scope, elem, attrs, demoCtrl) {
                var defaultTemplatePath = 'app/directives/demo/templates/default.tpl.html',
                    templatePath = defaultTemplatePath.replace(/default/, demoCtrl.provider.id),
                    template;

                template = $templateCache.get(templatePath) || $templateCache.get(defaultTemplatePath);
                $compile(elem.html(template).contents())(scope);
            },
            scope: {
                provider: '='
            }
        };
    });

Method 1b: use compiler

angular.module('ng-cherie.directives.demo.directive', [])
    .directive('demo', function demoDirective($compile, $templateCache) {
        return {
            bindToController: true,
            controller: 'DemoCtrl as demoCtrl',
            link: function demoLink(scope, elem, attrs, demoCtrl) {
                var defaultTemplatePath = 'app/directives/demo/templates/default.tpl.html',
                    templatePath = defaultTemplatePath.replace(/default/, demoCtrl.provider.id),
                    template;

                template = $templateCache.get(templatePath) || $templateCache.get(defaultTemplatePath);
                elem.append($compile(template)(scope));
            },
            scope: {
                provider: '='
            }
        };
    });

Method 2: use ng-include

angular.module('ng-cherie.directives.demo.directive', [])
    .directive('demo', function demoDirective() {
        return {
            bindToController: true,
            controller: 'DemoCtrl as demoCtrl',
            scope: {
                provider: '='
            },
            templateUrl: 'app/directives/demo/templates/demo.tpl.html'
        };
    });

where app/directives/demo/templates/demo.tpl.html is

<ng-include src="demoCtrl.showTemplate()"></ng-include>

where showTemplate() determines which template to show depending on the provider (similar to demoLink())

————————————>>>>>>————————————
in default.tpl.html:
use a directive (demoDescription directive) to pass in the description and a control to show the description, so that when demo directive (see above) renders the default template directly without the description, it won’t fail on missing transclusion.

<p class="demo-description" ng-transclude ng-if="demoDescriptionCtrl.isTemplateUsedWithDirective"></p>

call the directive:

<demo-description>
    {{ 'Provider description here.' | translate }}
</demo-description>

————————————>>>>>>————————————
jasmine test

describe('Demo directive', function() {
    var _,
        $compile,
        element,
        providerMockData,
        scope;

    beforeEach(module('ng-cherie.directives.demo'));
    beforeEach(module('ng-cherie.mocks.provider'));

    beforeEach(inject(function($injector) {
        _ = $injector.get('_');
        $compile = $injector.get('$compile');
        scope = $injector.get('$rootScope').$new();
        providerMockData = $injector.get('providerMockData');
    }));

    beforeEach(function() {
        scope.provider = _.first(providerMockData.providers);
    });

    function compileDirective(scope) {
        var compiledElement = $compile('<demo provider="provider"></demo>')(scope);

        scope.$digest();

        return compiledElement;
    }

    describe('compiled markup', function() {
        it('contains the expected markup', function() {
            element = compileDirective(scope);

            expect(element[0].querySelector('.demo-body')).not.toBeNull();
        });

        //some other tests here... mostly expecting certain classes to be or not be there

        it('shows the default template when the provider is unknown', function () {
            scope.provider.id = "unexpected_provider";
            element = compileDirective(scope);

            expect(element.find('demo-description').length).toBe(0);
        });
    });
});

Advertisements

would you like to leave a comment?

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s