Zack Argyle
Zack Argyle

Reputation: 8407

Share Directive Scope with Transcluded Elements

I am writing a reusable modal directive, but the transcluded elements create their own scope. Here is a JSFIDDLE of the issue. Here is how it works.

<button ng-click="show=!show">Show Modal</button>
<modal visible="show">
    <button ng-click="show=!show">X</button>
</modal>

Notice that the button to show it works, but the X does not close it, because the inner button is transcluded and creates its own scope. Is there any way to link the transcluded scope to the current scope of the directive? Or just stop it from creating its own scope? Here is the directive.

.directive('modal', function($compile) {
return {
  restrict: 'E',
  template: "<div ng-style='bgstyling()' ng-transclude></div>",
  transclude: true,
  link: function(scope, elem, attrs) {
    scope.$watch(attrs.visible, function(val) {
      elem[0].style.visibility = val ? 'visible' : 'hidden';   
    });
    scope.bgstyling = function() {
      return {
        'position': 'fixed',
        'top': '0',
        'left': '0',
        'bottom': '0',
        'right': '0',
        'backgroundColor': attrs.bgColor || '#000',
        'opacity': attrs.opacity || '0.85'
      }
    }
  }
}

})

* UPDATE *

I think the answer might have something to do with the transclude function parameter of the link function. This is what I just tried, but still isn't quite working.

link: function(scope, elem, attrs, nullC, transclude) {
    transclude(scope, function(clone) {
      elem.append($compile(clone)(scope));
    });
    ...

Upvotes: 1

Views: 135

Answers (2)

Gordon McAllister
Gordon McAllister

Reputation: 513

Making the controller responsible for updating the scope helps - the scope is shared after all and you probably want the logic for updating it in the same place.

.controller("testCtrl", function($scope) {
  $scope.show = false;
  $scope.toggle = function() {
    $scope.show = !$scope.show;
  };
})

And the template:

<div ng-app="test" ng-controller="testCtrl">
  <button ng-click="toggle()">Show Modal</button>
  <modal visible="show">
    <button ng-click="toggle()">X</button>
  </modal>
</div>

Check out this JSFiddle

Upvotes: 2

Asta
Asta

Reputation: 1579

The close button is specific to the Modal directive so you could just put the button in the directive html and avoid the scoping issue.

jsfiddle

...      
template: "<div ng-style='bgstyling()'><button ng-click=\"show=!show\">X</button></div>",
...

You can also access the parent scope if necessary but I prefer to try and keep scopes as simple as possible.

Edit You can still use transclude like in this jsfiddle

...
template: "
    <div ng-style='bgstyling()'>
        <button ng-click=\"show=!show\">X</button>
        <div ng-transclude></div>
    </div>
    ",
transclude: true,
...

Upvotes: 1

Related Questions