a suite of UI Components for development of web apps
Advanced User Interface Controls and Components
Created: 26 February 2015
By default HTML elements don’t have a context menu, and whenever a user clicks over element space using the right mouse button, the standard context menu for html page appears. In order to solve this problem, we can handle the right-click mouse button event and set to appear a custom popup window which will function as a context menu. However, this is time consuming process.
The ContextMenu directive for AngularJS solves this problem. It allows you to easily create and add a custom context menu to any other HTML element or directive. In following sections of this article we will show you how to create and add a different context menu to several different HTML elements: a button, an input element and a standard block element.
Similar: Custom ContextMenu Component for Angular 4
The use of ContextMenu directive is very simple. This directive is an attribute only directive, which means that it cannot act on its own, and must be applied to an existing HTML element or other directive in the DOM. Here is basic declaration of this directive:
<div iui-contextmenu menu-items="menuItems"></div>
As it can be seen from above declaration, in order to add menu items to the context menu directive we are using the menu-items attribute. This attribute accepts any array with menu item objects with following fields:
Here is an example:
// Context menu
$scope.menuItems = [
{ text: "Container", type: "header" },
{ key: "MENU_ITEM1", text: "Menu Item 1", itemClick: function(e){ alert('Menu Item 1 clicked!') } },
{ key: "MENU_ITEM2", text: "Menu Item 2", itemClick: function(e){ alert('Menu Item 2 clicked!'} },
{ key: "MENU_ITEM3", text: "Menu Item 3", itemClick: function(e){ alert('Menu Item 3 clicked!') } }
]
The itemClick function has one parameter e, which contains the menu item object. By using this object, we can determine which item is clicked. Let’s see how this works with real example.
Related: How to Display Context Menu in TreeView AngularJS
In case of input element, we will create a context menu which will copy/paste the text of the input field.
<input type="text" iui-contextmenu menu-items="editContextMenu" ng-model="sampleText" ng-disabled="editDisabled" ng-hide="isHidden"/>
An example of context menu for the input element:
$scope.sampleText = "Hello World!";
$scope.editDisabled = false;
$scope.isHidden = false;
// Context menu for input element
$scope.editContextMenu = [
{ text: "Text Editor", type: "header" },
{ key: 'EDIT_CUT', text: "Cut", itemClick: function(e){ return $scope.processEditClicks(e.item); } },
{ key: 'EDIT_COPY', text: "Copy", itemClick: function(e){ return $scope.processEditClicks(e.item); } },
{ key: 'EDIT_PASTE', text: "Paste", itemClick: function(e){ return $scope.processEditClicks(e.item); } }
]
// A function which processes all clicks in context menu for a input element
$scope.processEditClicks = function(item){
if (item){
if (localStorage){
switch (item.key){
case 'EDIT_CUT':
localStorage.setItem("sampleText", $scope.sampleText);
$scope.sampleText = '';
$scope.$apply();
break;
case 'EDIT_COPY':
localStorage.setItem("sampleText", $scope.sampleText);
break;
case 'EDIT_PASTE':
$scope.sampleText = localStorage.getItem("sampleText");
$scope.$apply();
break;
}
}
}
}
Depending on which menu item is clicked, the value of input field will be cut, copy or paste. Instead of using the window clipboard in our case we are using the HTML5 local storage functionality.
In case of a button element, in order to assign a context menu to it, we need to set the ContextMenu directive in the button declaration:
<button type="button" iui-contextmenu menu-items="btnContextMenu" ng-hide="isHidden">Button</button>
And the structure of context menu for the button will look like:
// Context menu data for Button
$scope.btnContextMenu = [
{ text: "Button", type: "header" },
{ key: 'EDIT_ENABLE', text: "Enable Editor", enabled: false, itemClick: function(e){ return $scope.processButtonClicks(e.item); } },
{ key: 'EDIT_DISABLE', text: "Disable Editor", itemClick: function(e){ return $scope.processButtonClicks(e.item); } },
{ type: "separator" },
{ key: 'EDIT_RESET', text: "Reset", itemClick: function(e){ return $scope.processButtonClicks(e.item); } }
]
// A function which processes all clicks in context menu for a button element
$scope.processButtonClicks = function(item){
if (item){
switch (item.key){
case 'EDIT_ENABLE':
$scope.editDisabled = false;
$scope.$apply();
item.enabled = false;
$scope.btnContextMenu[2].enabled = true;
break;
case 'EDIT_DISABLE':
$scope.editDisabled = true;
$scope.$apply();
item.enabled = false;
$scope.btnContextMenu[1].enabled = true;
break;
case 'EDIT_RESET':
$scope.sampleText = 'Hello World!';
$scope.editDisabled = false;
$scope.$apply();
$scope.btnContextMenu[1].enabled = false;
$scope.btnContextMenu[2].enabled = true;
break;
}
}
}
In our example, whenever a menu item from context menu of the button is clicked, input element will become enabled, disabled or restored to initial settings.
At last the input and button elements are placed inside a container element (we are using the <div> element).
<div class="block" iui-contextmenu menu-items="blockContextMenu">
<input type="text" iui-contextmenu menu-items="editContextMenu" ng-model="sampleText" ng-disabled="editDisabled" ng-hide="isHidden"/>
<button type="button" iui-contextmenu menu-items="btnContextMenu" ng-hide="isHidden">Button</button>
</div>
.block
{
background: #f5f5f5;
border: thin solid gray;
padding: 20px;
width: 300px;
height: 75px;
}
For this element we are going to use a different context menu, which looks like:
// Context menu for Div element
$scope.blockContextMenu = [
{ text: "Container", type: "header" },
{ key: 'ELEM_SHOW', text: "Show Content", enabled: false, itemClick: function(e){ return $scope.processContainerClicks(e.item); } },
{ key: 'ELEM_HIDE', text: "Hide Content", itemClick: function(e){ return $scope.processContainerClicks(e.item); } }
]
// A function which processes all clicks in context menu for a div element
$scope.processContainerClicks = function(item){
if (item){
switch (item.key){
case 'ELEM_SHOW':
$scope.isHidden = false;
$scope.$apply();
item.enabled = false;
$scope.blockContextMenu[2].enabled = true;
break;
case 'ELEM_HIDE':
$scope.isHidden = true;
$scope.$apply();
item.enabled = false;
$scope.blockContextMenu[1].enabled = true;
break;
}
}
}
This context menu shows or hides the child elements of the div element. For this purpose, we are using the isHidden variable in our application scope, which is linked to the ng-hide attribute of input and button elements.
As it is shown in above demonstration, whenever a right-click is made over input, button or div element, different context menu will pop-up. The appearance of the menu is determined by small set of CSS styles which can be changed and further customized to better match the appearance of your application.