BarakChamo
BarakChamo

Reputation: 3565

AngularJS : Scope access between directives and transcluded directives

I built a small demo of a modular form, consisting of individual input directive in it. It also has a preview of the form values, bound to the same controller and scope.

The input directives that cause the issue are the inputs that are transcluded inside the form:

<mailer-form>
  <mailer-input form="mail" model="email">
    <input class="form-control" placeholder="Email" ng-model="mail.email">
  </mailer-input>
</mailer-form>

<mailer-preview></mailer-preview>

You can take a look at it here:

http://plnkr.co/edit/0FuzfOFFDN5XcNyZcpBv

The problem is that ng-models in the form's template update the parent scope, while the transcluded inputs don't. That's why the first email input doesnt work and the rest do.

How can I make the transcluded directives bind both ways?

Thanks!

Upvotes: 0

Views: 90

Answers (1)

runTarm
runTarm

Reputation: 11547

The ng-transclude directive always create a new child scope for the transcluded content.

There is a request here (https://github.com/angular/angular.js/issues/5489) to not create a new scope but it hasn't implemented yet.

If you want the transcluded content to have the same scope as the container, you can use the transcludeFn in link() like the below snippet instead of ng-transclude.

link: function(scope, element, attributes, controllers, transcludeFn){
  transcludeFn(scope, function(nodes) {
    element.find('.transclude-here').append(nodes);
  })
}

and replace those

<div ng-transclude></div>

with

<div class="transclude-here"></div>

For the full example, see http://plnkr.co/edit/WYCOxC9xBIOTUWPs2iAq?p=preview

Edit: if you want this behavior in multiple places, you can write your own customized version of ng-transclude like this:

app.directive('myTransclude', function () {
  return {
    restrict: 'EAC',
    link: function(scope, element, attrs, controllers, transcludeFn) {
      transcludeFn(scope, function(nodes) {
        element.empty();
        element.append(nodes);
      });
    }
  };
});

and in html template:

 <div my-transclude></div>

Upvotes: 2

Related Questions