Search code examples
angularjsangularjs-directiveangularjs-ng-transclude

Use ng-model with a primitive value inside ng-transclude


In a legacy project, I want to create a new directive that uses transclude.

A trimmed down version of the directive code is:

app.directive('controlWrap', function() {
    return {
        restrict: 'E',
        transclude: true,
        scope: { label: "@" },
        templateUrl: "control-wrap-template.html"
    }
})

And the template is:

<div>
    <label>{{label}}</label>
    <div>
        <ng-transclude></ng-transclude>
    </div>
</div>

This directive is used like this

<control-wrap label="Just a example">
    <input type="text" ng-model="input" />
</control-wrap>
Test: {{input}}

I know that the workaround is to use a object in the scope instead of primitive value (ng-model inside ng-transclude). But that is no option for me. It is a ugly, poorly coded, legacy code that relies in those attributes directly on the scope.

Is there a something I can do in the directive to make that html works without change?


Solution

  • You can manually transclude (instead of using ng-transclude) and apply whatever scope (which is, in your case, scope.$parent) you need to the transcluded content:

    transclude: true,
    scope: { label: "@" },
    template: '<div>\
                 <label>{{label}}</label>\
                 <placeholder></placeholder>\
               </div>',
    link: function(scope, element, attrs, ctrls, transclude){
       transclude(scope.$parent, function(clone){
          element.find("placeholder").replaceWith(clone);
       });
    }
    

    Demo