Compile directive before template is rendered

1.6k views Asked by At

I'm making a directive for a States Select in angular. It's working, but I spent a while trying to figure out a way to compile the template before it's in the DOM. It currently works like this:

 app.register.directive('stateDropdown', ['StatesFactory', '$compile', function (StatesFactory, $compile) {
        function getTemplate(model) {
            var html = '<select ng-model="' + model + '" ng-options="state.abbreviation as state.name for state in states" class="form-control"></select>';
            return html;
        }

        function link (scope, element, attrs) {
            scope.states = StatesFactory.States;
            element.html(getTemplate(attrs.stateModel));
            $compile(element.contents())(scope);
        }
        return {
            replace: true,
            link: link

        }
    }]);

But as such it inserts the template into the element THEN compiles it against scope. Is there a better way to do this? Such as compiling the template before it's even inserted?

1

There are 1 answers

2
Enzey On BEST ANSWER

Scratch what I had before.

[Edit 2]

Using a dynamic model is a bit problematic trying to fit it into the normal Angular workflow. Instead you will need to compile the template in the directive by hand but add the ng-model before doing so, You will also need to manage the replacement of the existing element with the built template.

module.directive('stateDropdown', function (StatesFactory, $compile) {

    var template = '<select ng-options="state.abbreviation as state.name for state in states" class="form-control"></select>';
    return {
        scope: true,
        controller: function($scope) {
            $scope.states = StatesFactory.states;
        },
        compile: function($element, $attrs) {
            var templateElem = angular.element(template).attr('ng-model', '$parent.' + $attrs.stateModel);
            $element.after(templateElem);
            $element.remove();
            var subLink = $compile(templateElem);
            return {
                pre: function(scope, element, attrs) {
                    subLink(scope);
                },
                post: function(scope, element, attrs) {
                }
            }
        }
    };

});

A working example of this can be found here: http://jsfiddle.net/u5uz2po7/2/

The example uses an isolated scope so that applying the 'states' to the scope does not affect existing scopes. That is also the reason for the '$parent.' in the ng-model.