I'm trying to extend the angular-ui tabset functionality and I'm running into issues with wrapping it.
This plunker is the tabset directive un-wrapped:
http://plnkr.co/edit/AhG3WVNxCal5fZOUbSu6?p=preview
This plunker contains my first attempt at wrapping the tabset directive:
http://plnkr.co/edit/naKXbeVOS8nizwDPUrkT?p=preview
The initial wrapping approach is straight-forward wrapping. But... I introduce extra divs in the replacement template to avoid the "Multiple directives asking for isolated scope" and "Multiple directives asking for transclusion" angular errors and to make sure transclusion happens.
Key code snippets:
.directive('urlTabset', function() {
return {
restrict: 'E',
transclude: true,
replace: true,
scope: {
tabManager: '='
},
controller: [ "$scope", function($scope) {
var tabManager = $scope.tabManager;
}],
template:
'<div>' +
'<tabset>' +
'<div ng-transclude>' +
'</div>' +
'</tabset>' +
'</div>'
};
})
.directive('urlTab', function() {
return {
require: '^urlTabset',
restrict: 'E',
transclude: true,
replace: true,
scope: { tabName: '@' },
link: function(scope, element, attrs, urlTabsetCtrl) {
},
template:
'<div>' +
'<tab>' +
'<div ng-transclude>' +
'</div>' +
'</tab>' +
'</div>'
};
});
However, I think the extra divs in the template are causing issues. Here is the unwrapped tabset with extra divs in the places my template would add them.
http://plnkr.co/edit/kjDs7xJcZqltCAqUSAmX?p=preview
So the logical thing is to eliminate the divs... but this is where I need the help. Does anyone know of a clean way to do this without hitting the "Multiple directives asking for isolated scope" and "Multiple directives asking for transclusion" angular errors. Here is one failed attempt.
http://plnkr.co/edit/0C6lFNhfdTVcF7ahuN3G?p=preview
Error: Multiple directives [urlTab, tab] asking for transclusion on: <tab class="ng-isolate-scope ng-scope">
BTW, in case you're wondering what I'm trying to do, my end goal is to use the tabManager attribute passed to urlTabset to auto-populate fields in the tab directive (wrapped by urlTab). To be more concrete this is what I'm aiming for:
.directive('urlTab', function() {
return {
require: '^urlTabset',
restrict: 'E',
transclude: true,
replace: true,
scope: { tabName: '@' },
link: function(scope, element, attrs, urlTabsetCtrl) {
scope.tabs = urlTabsetCtrl.tabs;
scope.tabSelected = urlTabsetCtrl.tabSelected;
},
template:
'<tab active="tabs[tabName].active" disabled="tabs[tabName].disabled" select="tabSelected(tabName)" ng-transclude>' +
'</tab>'
};
});
The template above obviously does not work, but it gives you the gist of what I'm trying to do.
And I'm okay with a solution that requires the wrapping directive not have an isolated scope. I can get around this by storing state in the controller context.
If you are trying to augment angular-ui
's functionality, you may be better off doing it with attribute directives rather than brand new elements. I may be mistaken but it looks like you're not intending to alter the general stucture of the DOM other than to replace your directive with angular-ui's ones. For instance, using the HTML
<tabset url-tabset>
<tab url-tab>
<tab-heading>
<i class="icon-list"></i> Details
</tab-heading>
Details content.
</tab>
<tab url-tab>
<tab-heading>
<i class="icon-thumbs-up"></i> Impact
</tab-heading>
Impact tab content.
</tab>
</tabset>
would mean you no longer need to perform any transclusion or template replacement. This would avoid that problem all together.
This leaves the problem of isolated scope for attributes you want to use for the augmentation. Instead of using this, you can use scope: true
to grab the same isolated scope as tab
and tabset
(though you cannot define bindings here) and you can get attributes as you would use normal bound values by using $parse
and attrs
.
Your directives (with the functionality from your second plunker) then end up looking something like this.
angular.module('plunker', ['ui.bootstrap'])
.directive('urlTabset', function() {
return {
restrict: 'A',
require: 'tabset', // Confirm the directive is only being used on tabsets
controller: [ "$scope", "$attrs", function($scope, $attrs) {
var tabManagerGetter = $parse($attrs.tabManager); // '='
this.getTabManager = function() {
return tabManagerGetter($scope);
};
// fun stuff here
}]
};
})
.directive('urlTab', function() {
return {
require: ['tab', '^urlTabset'],
restrict: 'A',
link: function(scope, element, attrs, ctrls) {
var urlTabsetCtrl = ctrls[1];
function getTabName() {
return attrs.tabName; // '@'
}
var tabManager = urlTabsetCtrl.getTabManager();
// fun stuff here
}
};
});
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With