{{tab.body}}
a suite of UI Components for development of web apps
Advanced User Interface Controls and Components
Created: 08 December 2015
Whenever a tab of IntegralUI TabStrip directive is right-clicked, the browser context menu will appear by default. We can override this by creating a custom context menu that will appear on right-click over each tab header.
Similar: TabStrip Component for Angular 2
{{tab.body}}
In above demo, whenever tab header is right-clicked a custom context menu will popup with several different options explained below.
At first, we need to create and add a menu to each tab header. For this purpose, we will use the IntegralUI ContextMenu directive.
The use of this directive is simple, it is an attribute only directive that can be applied to any HTML element or other angular directives. In our case we need to apply it to each tab header.
angular
.module("appModule", ["integralui"])
.controller("appCtrl", ["$scope", "IntegralUITabStripService", "$timeout", function($scope, $ctrlService, $timeout){
// A unique identifer for the TabStrip
$scope.ctrlName = ctrlSample";
// An object that holds tabs
$scope.tabs = [
{
name: 'tab1',
text: 'Tab 1',
body: 'Curabitur pretium tincidunt lacus. Nulla gravida orci a odio. Nullam varius, turpis et commodo pharetra, est eros bibendum elit, nec luctus magna felis sollicitudin mauris. Integer in mauris eu nibh euismod gravida. Duis ac tellus et risus vulputate vehicula. Donec lobortis risus a elit. Etiam tempor.'
},
{
name: 'tab2',
text: 'Tab 2',
body: 'Pellentesque malesuada nulla a mi. Duis sapien sem, aliquet nec, commodo eget, consequat quis, neque. Aliquam faucibus, elit ut dictum aliquet, felis nisl adipiscing sapien, sed malesuada diam lacus eget erat. Cras mollis scelerisque nunc. Nullam arcu. Aliquam consequat.'
},
{
name: 'tab3',
text: 'Tab 3',
body: 'Fusce convallis, mauris imperdiet gravida bibendum, nisl turpis suscipit mauris, sed placerat ipsum urna sed risus. In convallis tellus a mauris. Curabitur non elit ut libero tristique sodales. Mauris a lacus. Donec mattis semper leo. In hac habitasse platea dictumst.'
}
];
}]);
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="css/integralui.tabstrip.css" />
<link rel="stylesheet" href="css/integralui.contextmenu.css" />
<link rel="stylesheet" href="css/themes/theme-flat-blue.css" />
<script type="text/javascript" src="external/angular.min.js"></script>
<script type="text/javascript" src="js/angular.integralui.min.js"></script>
<script type="text/javascript" src="js/angular.integralui.tabstrip.min.js"></script>
<script type="text/javascript" src="js/angular.integralui.contextmenu.min.js"></script>
</head>
<body>
<div ng-app="appModule" ng-controller="appCtrl">
<iui-tabstrip name="{{ctrlName}}" class="directive" tabs="tabs" iui-contextmenu="tabMenu" tab-added="onTabAdded(e)" tab-removed="onTabRemoved(e)">
<iui-tab ng-repeat="tab in tabs" name="{{tab.name}}">
<iui-tab-header iui-contextmenu="tabMenu">
{{tab.text}}
</iui-tab-header>
<p class="custom-content">{{tab.body}}</p>
</iui-tab>
</iui-tabstrip>
</div>
</body>
</html>
.custom-content
{
margin: 0;
padding: 5px;
}
.iui-contextmenu-block
{
border-radius: 0;
padding: 2px;
}
.iui-contextmenu-item
{
width: 140px;
}
.icons
{
margin-right: 5px;
vertical-align: middle;
}
.check-mark
{
background-position: -96px -48px;
}
From HTML specification we can see that a custom object called tabMenu is applied to the context menu directive. This object holds all menu options and events. In our example we will add add/remove functionality and option to show/hide tabs through menu options (explained below).
We can add or remove tabs from the menu. For this purpose we will add several menu options and attach a different operation to each option.
Related: Add or Remove Tabs in TabStrip for AngularJS
In our presentation, there are four add/remove options:
For each menu, we need to add a unique identifier (the key field), which will allow us to make a distinction and determine which option is clicked. When menu item is clicked, the itemClick event is fired. We can handle this event and add our operation.
var tabCount = $scope.tabs.length;
// Gets the currently selected tab in the tabstrip
var getCurrentSelection= function(){
return $ctrlService.selectedTab($scope.ctrlName);
}
// Creates a new tab
var createNewTab = function(){
tabCount++;
return { name: "tab" + tabCount, text: "Tab " + tabCount, body: 'Tab ' + tabCount + " Content" };
}
// Default menu options for adding tabs
var defaultMenuItems = [
{ text: 'Add Tab', key: 'ADD_TAB' },
{ text: 'Insert Tab Before', key: 'INSERT_TAB_BEFORE' },
{ text: 'Insert Tab After', key: 'INSERT_TAB_AFTER' },
{ text: 'Remove Tab', key: 'REMOVE_TAB', enabled: $scope.visibleTabs > 0 }
];
// Menu object that holds all menu options for the tabstrip context menu
$scope.tabMenu = {
itemIcon: 'icons empty',
items: defaultMenuItems,
itemClick: function(e){
if (e.item){
$ctrlService.suspendLayout($scope.ctrlName);
var selTab = getCurrentSelection();
switch (e.item.key){
case 'ADD_TAB':
$ctrlService.addTab($scope.ctrlName, createNewTab());
break;
case 'INSERT_TAB_BEFORE':
$ctrlService.insertTabBefore($scope.ctrlName, createNewTab(), getCurrentSelection());
break;
case 'INSERT_TAB_AFTER':
$ctrlService.insertTabAfter($scope.ctrlName, createNewTab(), getCurrentSelection());
break;
case 'REMOVE_TAB':
$ctrlService.removeTab($scope.ctrlName, getCurrentSelection());
break;
}
$ctrlService.resumeLayout($scope.ctrlName);
}
}
}
We are using a built-in function for each operation. These functions are part of IntegralUITabStripService. Here is a link with more information about which methods are supported.
Our context menu also contains options that allow you to show or hide tabs. This submenu is created dynamically, to reflect any changes to the number of tabs and their visibility. Whenever there is a change, the menu is updated.
For each tab, a menu option is created displaying the tab title and an icon showing whether the tab is visible or hidden. When some of these options is clicked, the corresponding tab will change its visibility status. Here how this looks like in code:
var getNextTab = function(tab){
var foundTab = null;
var index = $scope.tabs.indexOf(tab);
for (var i = index+1; i < $scope.tabs.length; i++){
if ($scope.tabs[i].visible != false){
foundTab = $scope.tabs[i];
break;
}
}
if (!foundTab){
for (var i = index-1; i >= 0; i--){
if ($scope.tabs[i].visible != false){
foundTab = $scope.tabs[i];
break;
}
}
}
return foundTab;
}
// Menu options for tab visibility
$scope.tabMenu = {
itemIcon: 'icons empty',
items: [],
itemClick: function(e){
if (e.item){
$ctrlService.suspendLayout($scope.ctrlName);
var selTab = getCurrentSelection();
switch (e.item.key){
default:
var index = visibilityMenuItems.indexOf(e.item);
if (index >= 0 && index < $scope.tabs.length){
$scope.tabs[index].visible = $scope.tabs[index].visible == undefined ? false : !$scope.tabs[index].visible;
// Make sure correct tab is selected
if ($scope.tabs[index].visible != false)
$ctrlService.selectedTab($scope.ctrlName, $scope.tabs[index]);
else if ($scope.tabs[index] == selTab)
$ctrlService.selectedTab($scope.ctrlName, getNextTab(selTab));
}
break;
}
updateMenu();
$ctrlService.resumeLayout($scope.ctrlName);
}
}
}
By hiding a specific tab, we are also updating the current selection so that there is always some visible tab selected. This is required for hiding the currently selected tab. We are searching through all visible tabs to get the next tab that will become selected.
var visibilityMenuItems = [];
var getCheckIcon = function(tab){
return tab.visible != false ? 'icons check-mark' : null;
}
// Updates the options in context menu
var updateMenu = function(){
$scope.tabMenu.items.length = 0;
$scope.visibleTabs = 0;
for (var i = 0; i < defaultMenuItems.length; i++)
$scope.tabMenu.items.push(defaultMenuItems[i]);
visibilityMenuItems.length = 0;
var menuItem = { type: "separator" };
if ($scope.tabs.length > 0){
$scope.tabMenu.items.push(menuItem);
for (var i = 0; i < $scope.tabs.length; i++){
menuItem = {
icon: getCheckIcon($scope.tabs[i]),
text: $scope.tabs[i].text
}
if ($scope.tabs[i].visible != false)
$scope.visibleTabs++;
visibilityMenuItems.push(menuItem);
$scope.tabMenu.items.push(menuItem);
}
}
$scope.tabMenu.items[1].enabled = $scope.visibleTabs > 0;
$scope.tabMenu.items[2].enabled = $scope.visibleTabs > 0;
$scope.tabMenu.items[3].enabled = $scope.visibleTabs > 0;
}
To simplify our example, we were using the same context menu for all tabs. However, you can add a different menu to each tab separately. In similar way, you can add a context menu to the TabStrip as a whole.
Adding a custom context menu to tabs in Angular TabStrip directive is easy. By using the context menu directive and specifying a menu object that holds all options and their functionality, you can override the default context menu with your own.