src/utils/transclude-directive.js
/**
* @ngdoc directive
* @name patternfly.utils.directive:pfTransclude
* @restrict A
* @element ANY
* @param {string} pfTransclude specifies the type of transclusion to use.<br/>
* <strong>Values:</strong>
* <ul style='list-style-type: none'>
* <li> 'sibling' - The transcluded contents scope is a sibling one to the element where transclusion happens (default)
* <li> 'parent' - The transcluded contents scope is that of the element where transclusion happens.
* <li> 'child' - The transcluded contents scope is child scope to the scope of the element where transclusion happens.
* </ul>
*
* @description
* Directive for transcluding in directives and setting up scope of children of parent directives. This is a workaround
* for https://github.com/angular/angular.js/issues/5489
*
* @example
<example module="patternfly.utils">
<file name="index.html">
<div ng-controller="UtilCtrl" class="row pf-transclude-example" style="display:inline-block; width: 100%;">
<span>Here the scope id is: <id>{{$id}}</id></span>
<transclude-sibling class="pf-transclude-example">
<pre>This content was transcluded using <b>pf-transclude</b> or <b>pf-transclude="sibling"</b>.</pre><pre>Its scope is: <id>{{$id}}</id> the parent of which is <id>{{$parent.$id}}</id></pre>
</transclude-sibling>
<transclude-parent>
<pre>This content was transcluded using <b>pf-transclude="parent"</b>.</pre><pre>Its scope is: <id>{{$id}}</id> the parent of which is <id>{{$parent.$id}}</id></pre>
</transclude-parent>
<transclude-child>
<pre>This content was transcluded using <b>pf-transclude="child"</b>.</pre><pre>Its scope is: <id>{{$id}}</id> the parent of which is <id>{{$parent.$id}}</id></pre>
</transclude-child>
</div>
</file>
<file name="script.js">
angular.module('patternfly.utils')
.controller( 'UtilCtrl', function($scope) {
})
.config(function($provide){
$provide.decorator('ngTranscludeDirective', ['$delegate', function($delegate) {
// Remove the original directive
$delegate.shift();
return $delegate;
}]);
})
.directive( 'transcludeSibling', function() {
return {
restrict: 'E',
transclude: true,
scope: {},
template:
'<div>' +
'<p>I am a directive with scope <id>{{$id}}</id></p>' +
'<span pf-transclude></span>' +
'</div>'
}
})
.directive( 'transcludeParent', function() {
return {
restrict: 'E',
transclude: true,
scope: {},
template:
'<div>' +
'<p>I am a directive with scope <id>{{$id}}</id></p>' +
'<span pf-transclude="parent"></span>' +
'</div>'
}
})
.directive( 'transcludeChild', function() {
return {
restrict: 'E',
transclude: true,
scope: {},
template:
'<div>' +
'<p>I am a directive with scope <id>{{$id}}</id></p>' +
'<span pf-transclude="child"></span>' +
'</div>'
}
})
;
</file>
</example>
*/
angular
.module('patternfly.utils').directive('pfTransclude', function () {
'use strict';
return {
restrict: 'A',
link: function ($scope, $element, $attrs, controller, $transclude) {
var iChildScope;
var iScopeType;
if (!$transclude) {
throw new Error('pfTransclude - ' +
'Illegal use of pfTransclude directive in the template! ' +
'No parent directive that requires a transclusion found. ' +
'Element: {0}');
}
iScopeType = $attrs.pfTransclude || 'sibling';
switch (iScopeType) {
case 'sibling':
$transclude(function (clone) {
$element.empty();
$element.append(clone);
});
break;
case 'parent':
$transclude($scope, function (clone) {
$element.empty();
$element.append( clone );
});
break;
case 'child':
iChildScope = $scope.$new();
$transclude( iChildScope, function (clone) {
$element.empty();
$element.append( clone );
$element.on( '$destroy', function () {
iChildScope.$destroy();
});
});
break;
}
}
};
});