LIDOR SYSTEMS

Advanced User Interface Controls and Components

Custom Context Menu for Tabs in Angular

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.text}}

{{tab.body}}

TabStrip directive is part of IntegralUI Studio for Web
a suite of UI Components for development of web apps

In above demo, whenever tab header is right-clicked a custom context menu will popup with several different options explained below.

Create a Custom Context Menu for Tabs

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).

Dynamically Add/Remove Tabs using Menu Options

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:

  • Add Tab - will add a new tab at the end
  • Insert Tab Before - will add a new tab before currently selected tab
  • Insert Tab After - will add a new tab after currently selected tab
  • Remove Tab - will remove the currently selected tab

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.

Change Tab Visibility

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;

}

Conclusion

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.

Did you Like this Article?


Enter your e-mail address below and you will receive latest articles as well as news on upcoming events and special offers.