Skip to content

Instantly share code, notes, and snippets.

@hugsbrugs
Created May 6, 2015 08:39
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save hugsbrugs/c85a6b1c10d03e8cb0da to your computer and use it in GitHub Desktop.
Save hugsbrugs/c85a6b1c10d03e8cb0da to your computer and use it in GitHub Desktop.
Angular-ui bootstrap tabs letf
angular.module('ui.bootstrap.tabsleft', ["template/tabs/tabset-left.html","template/tabs/tab-left.html"])
.controller('TabsetLeftController', ['$scope', function TabsetLeftCtrl($scope) {
var ctrl = this,
tabs = ctrl.tabs = $scope.tabs = [];
ctrl.select = function(selectedTab) {
angular.forEach(tabs, function(tab) {
if (tab.active && tab !== selectedTab) {
tab.active = false;
tab.onDeselect();
}
});
selectedTab.active = true;
selectedTab.onSelect();
};
ctrl.addTab = function addTab(tab) {
tabs.push(tab);
// we can't run the select function on the first tab
// since that would select it twice
if (tabs.length === 1) {
tab.active = true;
} else if (tab.active) {
ctrl.select(tab);
}
};
ctrl.removeTab = function removeTab(tab) {
var index = tabs.indexOf(tab);
//Select a new tab if the tab to be removed is selected and not destroyed
if (tab.active && tabs.length > 1 && !destroyed) {
//If this is the last tab, select the previous tab. else, the next tab.
var newActiveIndex = index == tabs.length - 1 ? index - 1 : index + 1;
ctrl.select(tabs[newActiveIndex]);
}
tabs.splice(index, 1);
};
var destroyed;
$scope.$on('$destroy', function() {
destroyed = true;
});
}])
.directive('tabsetleft', function() {
return {
restrict: 'EA',
transclude: true,
replace: true,
scope: {
type: '@'
},
controller: 'TabsetLeftController',
templateUrl: 'template/tabs/tabset-left.html',
link: function(scope, element, attrs) {
scope.vertical = angular.isDefined(attrs.vertical) ? scope.$parent.$eval(attrs.vertical) : false;
scope.justified = angular.isDefined(attrs.justified) ? scope.$parent.$eval(attrs.justified) : false;
}
};
})
.directive('tableft', ['$parse', function($parse) {
return {
require: '^tabsetleft',
restrict: 'EA',
replace: true,
templateUrl: 'template/tabs/tab-left.html',
transclude: true,
scope: {
active: '=?',
heading: '@',
onSelect: '&select', //This callback is called in contentHeadingTransclude
//once it inserts the tab's content into the dom
onDeselect: '&deselect'
},
controller: function() {
//Empty controller so other directives can require being 'under' a tab
},
compile: function(elm, attrs, transclude) {
return function postLink(scope, elm, attrs, tabsetCtrl) {
scope.$watch('active', function(active) {
if (active) {
tabsetCtrl.select(scope);
}
});
scope.disabled = false;
if ( attrs.disabled ) {
scope.$parent.$watch($parse(attrs.disabled), function(value) {
scope.disabled = !! value;
});
}
scope.select = function() {
if ( !scope.disabled ) {
scope.active = true;
}
};
tabsetCtrl.addTab(scope);
scope.$on('$destroy', function() {
tabsetCtrl.removeTab(scope);
});
//We need to transclude later, once the content container is ready.
//when this link happens, we're inside a tab heading.
scope.$transcludeFn = transclude;
};
}
};
}])
.directive('tableftHeadingTransclude', [function() {
return {
restrict: 'A',
require: '^tableft',
link: function(scope, elm, attrs, tabCtrl) {
scope.$watch('headingElement', function updateHeadingElement(heading) {
if (heading) {
elm.html('');
elm.append(heading);
}
});
}
};
}])
.directive('tableftContentTransclude', function() {
return {
restrict: 'A',
require: '^tabsetleft',
link: function(scope, elm, attrs) {
var tab = scope.$eval(attrs.tableftContentTransclude);
//Now our tab is ready to be transcluded: both the tab heading area
//and the tab content area are loaded. Transclude 'em both.
tab.$transcludeFn(tab.$parent, function(contents) {
angular.forEach(contents, function(node) {
if (isTabHeading(node)) {
//Let tabHeadingTransclude know.
tab.headingElement = node;
} else {
elm.append(node);
}
});
});
}
};
function isTabHeading(node) {
return node.tagName && (
node.hasAttribute('tab-heading') ||
node.hasAttribute('data-tab-heading') ||
node.tagName.toLowerCase() === 'tab-heading' ||
node.tagName.toLowerCase() === 'data-tab-heading'
);
}
});
angular.module("template/tabs/tab-left.html", []).run(["$templateCache", function($templateCache) {
$templateCache.put("template/tabs/tab-left.html",
"<li ng-class=\"{active: active, disabled: disabled}\">\n" +
" <a href ng-click=\"select()\" tableft-heading-transclude>{{heading}}</a>\n" +
"</li>\n" +
"");
}]);
angular.module("template/tabs/tabset-left.html", []).run(["$templateCache", function($templateCache) {
$templateCache.put("template/tabs/tabset-left.html",
"<div>\n" +
"<div class=\"col-sm-3\">\n" +
" <ul class=\"nav nav-{{type || 'tabs'}}\" ng-class=\"{'nav-stacked': vertical, 'nav-justified': justified}\" ng-transclude></ul>\n" +
"</div>\n" +
"<div class=\"col-sm-8 col-sm-offset-1\">\n" +
" <div class=\"tab-content\">\n" +
" <div class=\"tab-pane\" \n" +
" ng-repeat=\"tab in tabs\" \n" +
" ng-class=\"{active: tab.active}\"\n" +
" tableft-content-transclude=\"tab\">\n" +
" </div>\n" +
" </div>\n" +
"</div>\n" +
"</div>\n" +
"");
}]);
@hugsbrugs
Copy link
Author

replace tabset by tabsetleft and tab by tableft :

<tabsetleft vertical="true" type="pills">

            <tableft>
                <tab-heading>
                    TAB HEADING
                </tab-heading>

                TAB CONTENT
            </tableft>

</tabsetleft>

Certainly not optimized but works for me.

I really would like to know how usefull is the vertical tabs from ui bootstrap (https://angular-ui.github.io/bootstrap/#/tabs) if we can't have content on the right !!! Except of course on a mobile phone ...

@gtesslerge
Copy link

Hi

We need tabs left with panels on the right.

any idea?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment