javascriptangularjsangularjs-directivetransclusion

Directive, wrap content and keep attributes on original element


I have a bit of trouble creating a directive that wraps the element (and its children) that the directive is applied to. I don't get why this seemingly common scenario should be so difficult considering how easy many other commonplace things are in AngularJS, so it could very well be that I'm missing something here.

What I want to do is to wrap a select element in a div. I'm using transclude to preserve the original select element and its content but I can't get it to work correctly.

The HTML looks like this:

<select mlb-select ng-options="opt.val as opt.text for opt in mlb" ng-model="mlbOpt"></select>

and my directive looks like this:

directiveModule.directive("mlbSelect", function(){
    return {
        template: '<div class="mlb-select">'
                    + '<select ng-transclude></select>'
                    + '</div>',
        transclude: 'element',
        replace: true
    }
});

The resulting HTML looks like this:

<div class="mlb-select ng-pristine ng-valid" mlb-select ng-options="opt.val as opt.text for opt in mlb" ng-model="mlbOpt">
    <select ng-transclude class="ng-scope"></select>
</div>

Of course, this is not what I want. Why are the properties of my select element added to the wrapping div and not the element I specify with the ng-transclude attribute? The select element needs to retain the ng-options and ng-model properties.

What do I need to do to accomplish this?


Solution

  • As far as I know, the only way to do this is to specify the directive with transclusion in a wrapper element, e.g.:

    <div mlb-select>
        <select ...></select>
    </div>
    

    Of course there is no point in doing this if youe case is exactly as above.

    Transclusion in the context of this question roughly works as:

    1. The transcluded content is the content of the element that has the directive with transclude: true; in your case the content of the <select>, which is empty!

    2. The transcluded content is placed inside the element that specifies ng-transclude in the template of the directive.