2

When I use Angularjs transclusion it seems to break styling which uses on child selector css rules. For instance below I'm creating the default Bootstrap panel directly:

<div class="panel panel-default">
    <div class="panel-heading">
        panel heading
    </div>
    <div class="panel-body">
        panel body
    </div>
</div>

But using Angularjs directives, in theory, I can hide the Bootstrap panel css like this...

<my-panel>
    <my-panel-heading>
        my panel heading
    </my-panel-heading>
    <my-panel-body>
        my panel body
    </my-panel-body>
</my-panel>

And maybe add some customisations. My directives would look like this...

angular.module('myApp')
.directive('myPanel', [ function() {
    var directive = {
        transclude: true,
        restrict: 'E',
        scope: {},
        template: '<div class="panel panel-default" ng-transclude></div>'
    }
    return directive;
}]);

angular.module('myApp')
.directive('myPanelHeading', [ function() {
    var directive = {
        transclude: true,        
        restrict: 'E',
        scope: {},        
        template: '<div class="panel-heading" ng-transclude></div>'
    }
    return directive;
}]);

angular.module('myApp')
.directive('myPanelBody', [ function() {
    var directive = {
        transclude: true,        
        restrict: 'E',
        scope: {},        
        template: '<div class="panel-body" ng-transclude></div>'
    }
    return directive;
}]);

Unfortunately the styling is now broken. When I examine the generated html, Angularjs has added tags to the html for the scope...

<my-panel>
  <div class="panel panel-default" ng-transclude="">
    <my-panel-heading class="ng-scope"> <!-- is this breaking the child selector rule? -->
     <div class="panel-heading" ng-transclude=""> 

I'm still new to Angularjs and CSS, so am I right about this? Is this what is causing the styling to break? And if so wouldn't this cause endless problems if you use Angularjs with Bootstrap or Foundation or is there a simple workaround? Here is the fiddle.

Any advice on avoiding this problem is much appreciated!

EDIT: Here's a screenshot of (what I think is) the relevant CSS from Bootstrap...

enter image description here

I'm guessing that the link between panel-heading and panel-default is broken?

CSharp
  • 1,396
  • 1
  • 18
  • 41

2 Answers2

3

Yes it breaks it because it insert extra tags, tell it to replace the tags instead by using the replace property in your directives configuration.

See the Update JS Fiddle

angular.module('myApp', []);

angular.module('myApp')
.directive('myPanel', [ function() {
    var directive = {
        transclude: true,
        replace: true,
        restrict: 'E',
        template: '<div class="panel panel-default" ng-transclude></div>'
    }
    return directive;
}]);

angular.module('myApp')
.directive('myPanelHeading', [ function() {
    var directive = {
        transclude: true,
        replace: true,
        restrict: 'E',
        template: '<div class="panel-heading" ng-transclude></div>'
    }
    return directive;
}]);

angular.module('myApp')
.directive('myPanelBody', [ function() {
    var directive = {
        transclude: true,   
        replace: true,     
        restrict: 'E',
        template: '<div class="panel-body" ng-transclude></div>'
    }
    return directive;
}]);
GillesC
  • 10,647
  • 3
  • 40
  • 55
  • Thanks! That does fix the problem. I read replace has been deprecated though, seems wrong to deprecate something as necessary as this? – CSharp Nov 03 '15 at 13:21
  • 1
    See this post about the subject http://stackoverflow.com/questions/24194972/why-is-replace-deprecated-in-angularjs – GillesC Nov 03 '15 at 13:30
  • 1
    Personally I tend to use directive as attribute only so my markup is accurate. Also in your case one would probably just create one directive which would build the panel in full instead of one directive per element. Like `Some text` for example. – GillesC Nov 03 '15 at 13:32
  • Thanks for the info. Very helpful! – CSharp Nov 03 '15 at 13:36
  • FYI There's not guaranteed support for replace in future iterations of angular. http://stackoverflow.com/questions/24194972/why-is-replace-deprecated-in-angularjs/24195251#24195251 – LessQuesar Feb 23 '16 at 16:09
2

Try adding replace: true, to your directives i.e. something like this:

angular.module('myApp', []);

angular.module('myApp')
.directive('myPanel', [ function() {
    var directive = {
        transclude: true,
        replace: true,
        restrict: 'E',
        template: '<div class="panel panel-default" ng-transclude></div>'
    }
    return directive;
}]);

angular.module('myApp')
.directive('myPanelHeading', [ function() {
    var directive = {
        transclude: true, 
        replace: true,
        restrict: 'E',
        template: '<div class="panel-heading" ng-transclude></div>'
    }
    return directive;
}]);
Harold Ship
  • 989
  • 1
  • 8
  • 14