Angular Dynamic Context Menu

Angular Dynamic Context Menu

"contextmenu" is an event like click, mouseup, mousemove, mousedown. This "contextmenu" event is typically triggered by clicking the right mouse button. By default, clicking right mouse button, you will get cut, copy, pase, inspect menus. In my program, i have created a custom context menu.

Let's start my dynamic context menu, it is dynamic because for different sections like List elements and Table, we have different context menu.

For List Elements, onListClick($event) event is called using contextmenu event. contextmenu is an event like onclick, onfocus events and is triggered by clicking right button.

For Table, onTableClick($event) event is called when contextmenu triggered.

app.component.html

<div class="container">
  <div class="row">
    <div class="col">
      <h4>List Elements</h4>
      <ul class="list">
        <li (contextmenu)="onListClick($event)">List Element 1</li>
        <li (contextmenu)="onListClick($event)">List Element 2</li>
        <li (contextmenu)="onListClick($event)">List Element 3</li>
        <li (contextmenu)="onListClick($event)">List Element 4</li>
      </ul>
    </div>
    <div class="col">
      <table class="table" (contextmenu)="onTableClick($event)">
        <thead>
          <tr>
            <th>Firstname</th>
            <th>Lastname</th>
            <th>Email</th>
          </tr>
        </thead>
        <tbody>
          <tr>
            <td>John</td>
            <td>Doe</td>
            <td>[email protected]</td>
          </tr>
          <tr>
            <td>Mary</td>
            <td>Moe</td>
            <td>[email protected]</td>
          </tr>
          <tr>
            <td>July</td>
            <td>Dooley</td>
            <td>[email protected]</td>
          </tr>
        </tbody>
      </table>
    </div>
  </div>


      <div #contextMenu></div>
</div>

<div #contextMenu></div> is needed to display contextmenu. Using Viewchild #contextMenu, we are going to create dynamic context menu inside the div.

app.component.ts

import { Component, OnInit, ComponentFactoryResolver, ViewChild, ViewContainerRef } from '@angular/core';
import { ContextmenuComponent } from './contextmenu/contextmenu.component';
@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit {
  title = 'contextmeu';
  rightClickMenuItems = [];
  parentElem: any;
  contextMenuSelector: string;
  menuEvent: any;


  @ViewChild('contextMenu', { read: ViewContainerRef, static: true }) container;


  constructor(private componentFactoryResolver: ComponentFactoryResolver) { }


  ngOnInit(): void {
  }


  onListClick(event) {
    console.log(event);
    this.menuEvent = event;
    this.contextMenuSelector = event.srcElement;
    this.rightClickMenuItems = [
      {
        menuText: 'Edit',
        menuLink: '',
      },
      {
        menuText: 'Delete',
        menuLink: '',
      },
    ];
    this.createContextMenuComponent();
  }
  onTableClick(event) {
    console.log(event);
    this.menuEvent = event;
    this.contextMenuSelector = event.srcElement;
    this.rightClickMenuItems = [
      {
        menuText: 'Cut',
        menuLink: '',
      },
      {
        menuText: 'Copy',
        menuLink: '',
      },
      {
        menuText: 'Paste',
        menuLink: '',
      },
    ];
    this.createContextMenuComponent();
  }


  createContextMenuComponent() {
    this.container.clear();
    const componentFactory = this.componentFactoryResolver.resolveComponentFactory(ContextmenuComponent);
    const componentRef = this.container.createComponent(componentFactory);
    (<ContextmenuComponent>componentRef.instance).contextMenuEvent = this.menuEvent;
    (<ContextmenuComponent>componentRef.instance).contextMenuSelector = this.contextMenuSelector;
    (<ContextmenuComponent>componentRef.instance).contextMenuItems = this.rightClickMenuItems;
  }


}

Here i am using ComponentFactoryResolver and createComponent to dynamically create the component inside DOM. Here three component instances (contextMenuEvent, contextMenuSelector, contextMenuItems) are sent to contextmenu component as @Input parameters.

contextmenu.component.html

<div class="contextMenu" tabindex="-1" aria-hidden="true">
  <ul *ngIf="isDisplayContextMenu">
    <li *ngFor="let menuItem of contextMenuItems; index as i"
    (click)="onContextMenuClick($event, menuItem.menuLink)">{{ menuItem.menuText }}</li>
  </ul>
  </div>

contextmenu.component.ts

import { Component, OnInit, Input, ElementRef, HostListener } from '@angular/core';


@Component({
  selector: 'app-contextmenu',
  templateUrl: './contextmenu.component.html',
  styleUrls: ['./contextmenu.component.css']
})
export class ContextmenuComponent implements OnInit {
  @Input() contextMenuEvent;
  @Input() contextMenuSelector;
  @Input() contextMenuItems;
  isDisplayContextMenu: boolean = false;
  _currentMenuVisible = null;


  constructor(private elementRef: ElementRef) {
    this.isDisplayContextMenu = false;
  }


  ngOnInit() {
    this.initContextMenu();
  }


  initContextMenu() {
    console.log(this.contextMenuSelector);
    console.log(this.contextMenuEvent);
    if (this.contextMenuSelector && this.contextMenuEvent) {
      this.contextMenuEvent.preventDefault();
      this.contextMenuEvent.stopPropagation();
      this.createContextMenu(this.contextMenuEvent.clientX, this.contextMenuEvent.clientY);
      this.contextMenuSelector.addEventListener('click', e => {
        this.closeCurrentlyOpenedMenu();
      });
    }
  }


  createContextMenu(x, y) {
    this.closeCurrentlyOpenedMenu();
    this.isDisplayContextMenu = true;
    if (this.isDisplayContextMenu && this.elementRef.nativeElement) {
      console.log(this.elementRef.nativeElement);
      const contextMenuDiv = this.elementRef.nativeElement.querySelector('.contextMenu');
      console.log(contextMenuDiv);
      if (contextMenuDiv) {
        this._currentMenuVisible = contextMenuDiv;
        contextMenuDiv.style.left = x + "px";
        contextMenuDiv.style.top = y + "px";
      }
    }
  }


  closeContextMenu(menu) {
    console.log(menu);
    menu.style.left='0px';
    menu.style.top='0px';
    this._currentMenuVisible = null;
  }


  closeCurrentlyOpenedMenu() {
    console.log(this._currentMenuVisible);
      if (this._currentMenuVisible !== null) {
          this.closeContextMenu(this._currentMenuVisible);
      }
  }


  /* close context menu on left click */
  @HostListener('document:click')
  documentClick(): void {
    this.isDisplayContextMenu = false;
  }


  /* close context menu on "ESC" key keypress */
  @HostListener('window:onkeyup')
  escKeyClick(): void {
    this.isDisplayContextMenu = false;
  }


}

contextMenuEvent, contextMenuSelector, contextMenuItems are @Input parameters.

contextMenuEvent - event for getting X and Y axis value of Selected element

contextMenuSelector - surceElement value to attach click event listener

contextMenuItems - pass content menu json

Source Url :

Live Url :


suresh kumar (w yadav)

Lead UI and Frontend Engineer | Master of Computer Applications - MCA at Swami Vivekananda Subharti University, Meerut

3 年

can you share about ag-grid in angular

回复
suresh kumar (w yadav)

Lead UI and Frontend Engineer | Master of Computer Applications - MCA at Swami Vivekananda Subharti University, Meerut

3 年
回复

要查看或添加评论,请登录

社区洞察

其他会员也浏览了