Context menu in Angular Gantt component

26 Aug 202517 minutes to read

The context menu in the Syncfusion Angular Gantt component provides right-click access to task and column operations, improving efficiency with contextual task actions. Menu items adapt based on the clicked element, such as task rows, column headers, or chart areas.

Enabling context menu

To enable the context menu, set the enableContextMenu property to true and import ContextMenuService from @syncfusion/ej2-angular-gantt in the provider section of AppModule.

The following items are available in the default context menu:

  • AutoFit: Adjusts the current column width to fit its content.
  • AutoFitAll: Adjusts all column widths to fit their content.
  • SortAscending: Sorts the current column in ascending order.
  • SortDescending: Sorts the current column in descending order.
  • TaskInformation: Opens the editing dialog for the selected task.
  • Add: Inserts a new task with sub-options: Above, Below, Child, Milestone.
  • Indent: Moves the selected task one level inward.
  • Outdent: Moves the selected task one level outward.
  • DeleteTask: Deletes the selected task.
  • Save: Commits changes to the edited task.
  • Cancel: Discards changes to the edited task.
  • SplitTask: Divides the selected task at the specified date.
  • MergeTask: Combines split task segments with sub-options: Left, Right.
  • Convert: Converts tasks with sub-options: To Milestone and To Task.
  • DeleteDependency: Deletes the selected task dependency.

The following example demonstrates context menu implementation with default items, where menu options adapt based on the clicked element and editSettings configuration.

import { NgModule } from '@angular/core'
import { BrowserModule } from '@angular/platform-browser'
import { GanttModule, ContextMenuService, EditService, SortService, ResizeService } from '@syncfusion/ej2-angular-gantt'
import { SelectionService } from '@syncfusion/ej2-angular-gantt'
import { Component, ViewEncapsulation, OnInit } from '@angular/core';
import { Gantt } from '@syncfusion/ej2-gantt';

@Component({
    imports: [GanttModule],
    providers: [SelectionService, ContextMenuService, EditService, SortService, ResizeService],
    standalone: true,
    selector: 'app-root',
    template:
        `<ejs-gantt id="ganttContextmenu" height="430px" [dataSource]="data" [taskFields]="taskSettings" [enableContextMenu]="true" [allowSorting]="true" [allowResizing]="true" [editSettings]="editSettings"></ejs-gantt>`,
    encapsulation: ViewEncapsulation.None
})

export class AppComponent {
    // Data for Gantt
    public data?: object[];
    public taskSettings?: object;
    public editSettings?: object;
    public ngOnInit(): void {
        this.data = [
            { TaskID: 1, TaskName: 'Project Initiation', StartDate: new Date('04/02/2019'), EndDate: new Date('04/21/2019'), },
            { TaskID: 2, TaskName: 'Identify Site location', StartDate: new Date('04/02/2019'), Duration: 4, ParentID: 1, Progress: 50 },
            { TaskID: 3, TaskName: 'Perform Soil test', StartDate: new Date('04/02/2019'), Duration: 4, ParentID: 1, Progress: 50 },
            { TaskID: 4, TaskName: 'Soil test approval', StartDate: new Date('04/02/2019'), Duration: 4, ParentID: 1, Progress: 50 },
            { TaskID: 5, TaskName: 'Project Estimation', StartDate: new Date('04/02/2019'), EndDate: new Date('04/21/2019'), },
            { TaskID: 6, TaskName: 'Develop floor plan for estimation', StartDate: new Date('04/04/2019'), Duration: 3, ParentID: 5, Progress: 50 },
            { TaskID: 7, TaskName: 'List materials', StartDate: new Date('04/04/2019'), Duration: 3, ParentID: 5, Progress: 50 },
            { TaskID: 8, TaskName: 'Estimation approval', StartDate: new Date('04/04/2019'), Duration: 3, ParentID: 5, Progress: 50 },
            { TaskID: 9, TaskName: 'Sign Contract', StartDate: new Date('04/04/2019'), Duration: 1, Predecessor: '8', Progress: 30 },
            { TaskID: 10, TaskName: 'Project Approval and kick off', StartDate: new Date('04/04/2019'), EndDate: new Date('04/21/2019'), Duration: 0, Predecessor: '9' },
        ];
        this.taskSettings = {
            id: 'TaskID',
            name: 'TaskName',
            startDate: 'StartDate',
            duration: 'Duration',
            progress: 'Progress',
            dependency: 'Predecessor',
            parentID: 'ParentID'
        };
        this.editSettings = {
            allowAdding: true,
            allowEditing: true,
            allowDeleting: true
        };
    }
}
import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import 'zone.js';
bootstrapApplication(AppComponent).catch((err) => console.error(err));

Note: If a required feature is not enabled, the related context menu item will be disabled or hidden to prevent unsupported actions.

Custom context menu items

Extend the context menu functionality by adding custom items using the contextMenuItems property. Custom items are defined as a collection of contextMenuItemModel objects with properties for id (unique identifier), text (display label), target (CSS selector for appearance context), and iconCss (icon styling class).

The target property determines where custom menu items appear: .e-content for task-related operations, like add, delete, save, and cancel, .e-gridheader for column-related operations.

The contextMenuOpen event enables dynamic modification, such as hiding items based on row selection. The contextMenuClick event handles custom item actions, providing details like the selected item’s id, text, and row data.

The following sample shows context menu items for parent rows to expand or collapse child rows in the content area and a context menu item to hide columns in the header area.

import { NgModule } from '@angular/core'
import { BrowserModule } from '@angular/platform-browser'
import { GanttModule, SortService, ResizeService } from '@syncfusion/ej2-angular-gantt'
import { SelectionService, ContextMenuService, EditService } from '@syncfusion/ej2-angular-gantt'
import { Component, ViewEncapsulation, OnInit, ViewChild } from '@angular/core';
import { Gantt } from '@syncfusion/ej2-gantt';
import { GanttComponent, ContextMenuClickEventArgs, ContextMenuOpenEventArgs } from '@syncfusion/ej2-angular-gantt';
import { ContextMenuItemModel } from '@syncfusion/ej2-grids';

@Component({
    imports: [GanttModule],
    providers: [SelectionService, ContextMenuService, EditService, SortService, ResizeService],
    standalone: true,
    selector: 'app-root',
    template:
        `<ejs-gantt #customcontextmenu id="ganttCustomContextmenu" height="430px" [dataSource]="data" [taskFields]="taskSettings" [enableContextMenu]="true" [contextMenuItems]="contextMenuItems" [allowSorting]="true" [allowResizing]="true" [editSettings]="editSettings" (contextMenuClick)="contextMenuClick($event)" (contextMenuOpen)="contextMenuOpen($event)"></ejs-gantt>`,
    encapsulation: ViewEncapsulation.None
})

export class AppComponent {
    // Data for Gantt
    public data?: object[];
    public taskSettings?: object;
    public editSettings?: object;
    public contextMenuItems?: (string | ContextMenuItemModel)[];
    @ViewChild('customcontextmenu', { static: true })
    public ganttObj?: GanttComponent | any;
    public ngOnInit(): void {
        this.data = [
            {
                TaskID: 1, TaskName: 'Project Initiation', StartDate: new Date('04/02/2019'), EndDate: new Date('04/21/2019'),
            },
            { TaskID: 2, TaskName: 'Identify Site location', StartDate: new Date('04/02/2019'), Duration: 4, ParentID: 1, Progress: 50 },
            { TaskID: 3, TaskName: 'Perform Soil test', StartDate: new Date('04/02/2019'), Duration: 4, ParentID: 1, Progress: 50 },
            { TaskID: 4, TaskName: 'Soil test approval', StartDate: new Date('04/02/2019'), Duration: 4, ParentID: 1, Progress: 50 },
            {
                TaskID: 5, TaskName: 'Project Estimation', StartDate: new Date('04/02/2019'), EndDate: new Date('04/21/2019'),
            },
            { TaskID: 6, TaskName: 'Develop floor plan for estimation', StartDate: new Date('04/04/2019'), Duration: 3, ParentID: 5, Progress: 50 },
            { TaskID: 7, TaskName: 'List materials', StartDate: new Date('04/04/2019'), Duration: 3, ParentID: 5, Progress: 50 },
            { TaskID: 8, TaskName: 'Estimation approval', StartDate: new Date('04/04/2019'), Duration: 3, ParentID: 5, Progress: 50 },
            { TaskID: 9, TaskName: 'Sign Contract', StartDate: new Date('04/04/2019'), Duration: 1, Predecessor: '8', Progress: 30 },
            {
                TaskID: 10, TaskName: 'Project Approval and kick off', StartDate: new Date('04/04/2019'),
                EndDate: new Date('04/21/2019'), Duration: 0, Predecessor: '9'
            },
        ];
        this.taskSettings = {
            id: 'TaskID',
            name: 'TaskName',
            startDate: 'StartDate',
            duration: 'Duration',
            progress: 'Progress',
            dependency: 'Predecessor',
            parentID: 'ParentID'
        };
        this.editSettings = {
            allowAdding: true,
            allowEditing: true,
            allowDeleting: true
        };
        this.contextMenuItems = ['AutoFitAll', 'AutoFit', 'TaskInformation', 'DeleteTask', 'Save', 'Cancel', 'SortAscending', 'SortDescending', 'Add', 'DeleteDependency', 'Convert',
            { text: 'Collapse the Row', target: '.e-content', id: 'collapserow' } as ContextMenuItemModel,
            { text: 'Expand the Row', target: '.e-content', id: 'expandrow' } as ContextMenuItemModel,
            { text: 'Hide Column', target: '.e-gridheader', id: 'hidecols' } as ContextMenuItemModel
        ];
    }

    public contextMenuClick(args: ContextMenuClickEventArgs) {
        let record = args.rowData;
        if (args.item.id === 'collapserow') {
            this.ganttObj.collapseByID(Number(record!.ganttProperties!.taskId));
        }
        if (args.item.id === 'expandrow') {
            this.ganttObj.expandByID(Number(record!.ganttProperties!.taskId));
        }
        if (args.item.id === 'hidecols') {
            this.ganttObj.hideColumn(args.column!.headerText);
        }
    }
    public contextMenuOpen(args: ContextMenuOpenEventArgs) {
        let record = args.rowData;
        if (args.type !== 'Header') {
            if (!record!.hasChildRecords) {
                args.hideItems!.push('Collapse the Row');
                args.hideItems!.push('Expand the Row');
            } else {
                if (record!.expanded) {
                    args.hideItems!.push("Expand the Row");
                } else {
                    args.hideItems!.push("Collapse the Row");
                }
            }
        }
    }
}
import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import 'zone.js';
bootstrapApplication(AppComponent).catch((err) => console.error(err));

This implementation shows custom context menu integration with event handling. The contextMenuClick event receives parameters including the selected item’s id, text, and the current row data, enabling specific actions based on the context.

Touch interaction

On touch devices, context menu functionality is accessible through long press gestures. Long press on task rows, headers, or chart areas opens the context menu, while tapping menu items executes associated actions. Items with sub-menus (e.g., Add, Convert) expand additional options when tapped, and tapping outside the menu closes it without performing actions.

This touch interaction ensures consistent experience across different device types and input methods while maintaining full functionality through intuitive gesture-based navigation.

For a comprehensive demonstration of context menu functionality, including default items, custom items, and sub-menus, explore the interactive sample.