34

How do you create a context menu in angular 4 ? Unfortunately the html context menu doesn't work.

So I want to create a component and display it on right click at the cursor coordinates but how do you implement this?

e.g.

<ul>
    <li (click)="showContextMenuComponent">example</li>
</ul
2
  • 1
    could you please explain a bit more or give us more details with a exemple of code with if posible please Commented Aug 15, 2017 at 22:29
  • There are many ways to implement a context menu in Angular. Probably easiest for you to use a component library, like ngx-context-menu. Also, please read how to ask a question for future reference, as if will improve our ability to help. Commented Aug 15, 2017 at 22:38

5 Answers 5

52

I found all your solutions quite complicated and hard to customize, and since i just started i wanted to solve this with components and eventbinding only. So My ContextMenu is a component with Input values x and y and is shown on right click on top of its ParentComponent :)

Stackblitz Example

So here it is:

Parent.component.ts

 export class parentComponent {
      contextmenu = false;
      contextmenuX = 0;
      contextmenuY = 0;

      //activates the menu with the coordinates
      onrightClick(event){
          this.contextmenuX=event.clientX
          this.contextmenuY=event.clientY
          this.contextmenu=true;
      }
      //disables the menu
      disableContextMenu(){
         this.contextmenu= false;
      }

parent.component.html

<!-- your whole html is wrapped in a div so anywhere you click you disable contextmenu,
also the div is responsible for suppressing the default browser contextmenu -->
<div (click)="disableContextMenu()" oncontextmenu="return false;">
    <!-- this is the usage -->
    <ul>
        <li (contextmenu)="onrightClick($event)">right click me!</li>
    </ul>

    <!--you have to write this only once in your component-->
    <div *ngIf="contextmenu">
        <app-contextmenu [x]="contextmenuX" [y]="contextmenuY"></app-contextmenu>
    </div>
</div>

This is the context menu itself:

contextmenu.component.ts

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

@Component({
  selector: 'app-contextmenu',
})
export class ContextmenuComponent{

  constructor() { }


  @Input() x=0;
  @Input() y=0;

}

contextmenu.component.html

<div class="contextmenu" [ngStyle]="{'left.px': x, 'top.px': y}">
  this is your contextmenu content
</div>

contextmenu.component.css

.contextmenu{
    position: absolute;
}

You can now apply your own animations, css styling, etc. as usual with a component. Hope this could help :) have fun !

Sign up to request clarification or add additional context in comments.

5 Comments

Cool! I'll do a context menu myself too. As soon as I finish it I'll post here my solution.
I have created custom one and put on git hub context menu is dynamic and hide on mouse out. github.com/ieammac/angular-4-custom-context-menu
I had to add event.PreventDefault() to the onrightClick() function. Otherwise both context-menu's would show.
Hi there, its looking cool..I've a small issue here with positions. On every right click x,y values are different here.Is that the behavior ??. Please guide me in this
I think @Naveen Kumar V solution is way better and works with ESC and click everywhere to remove works as oppose to this solution. See the demo here : stackblitz.com/edit/…
11

You can try ngx-contextmenu library. Check the demo here

If you are on angular version 4 consider using [email protected]

6 Comments

thank you! this is very interesting, I installed it and it worked,but how do you style the menu? css does not seem to affect it
how to style the context menu please check this issue github.com/isaacplmann/ngx-contextmenu/issues/41
This is for Angular 6, and not working with Angular 4
@N.K You can always try to run npm show ngx-contextmenu@* version and pick the old version of the library that works with your angular version.
@N.K you need to use one of the early versions as they targeting angular 4. If you check version 1.0.0 package.json it has angular 4 in its peerDependencies and devDependencies
|
8

SOLUTION: (tested with Angular 9):

In HTML:

<div (click)="itemClicked($event);" (contextmenu)="itemClicked($event);"> 
  Click Me!!!
</div>

In TS:

itemClicked($event) {
  console.log($event);
  /* Use the following properties to differentiate between left and right click respectively.
  * $event.type will be "click" or "contextmenu"
  * $event.which will be "1" or "3"
  */

  // To prevent browser's default contextmenu
  $event.preventDefault();
  $event.stopPropagation();

  // To show your modal or popover or any page
  this.openQuickDialog($event); // FYI, this line calls my other method to open Popover dialog.
}

Here is a live example using angular material menu. when you right click on an item, it will set the position of the menu to the mouse position and opens it.

I posted this answer; just in case it might help others like me.

Comments

1

Building further on the GREAT solution of User9132 (see above) you can build a context menu dynamically. In that way you can reuse the generic context menu component.

parent.component.html: Right click on a list item. Finally it is allowed to handle the selected menu item.

<div class="row mt-3 ml-1">
  <div class="col-11 col-sm-11 col-md-10" (click)="disableContextMenu()" oncontextmenu="return false;">
    <div class="geocache-list-height">
      <table id="geocaches-list" class="table">
        <tbody>
        <tr *ngFor="let geocache of mygeocaches" class="d-flex">
          ...
          <td class="col-1" (contextmenu)="onrightClick($event, geocache)"><i class="icon-ellipsis-vert"></i></td>
        </tr>
        </tbody>
      </table>
    </div>
  </div>
</div>
<!--you have to write this only once in your component-->
<div *ngIf="contextmenu==true">
  <app-contextmenu [x]="contextmenuX" [y]="contextmenuY" [menuitems]="showMenuOptions()" (menuItemSelected)="handleMenuSelection($event)"></app-contextmenu>
</div>

parent.component.ts: The parent determines the menu items and acts on the selected menu item. I started positioning the context menu on the screen so it won't fall off the screen. Maybe this needs improvements - you're welcome.

@Component({
    selector: 'app-geocache-list',
    templateUrl: './parent.component.html',
    styleUrls: ['./parent.component.css']
})
export class ParentComponent implements OnInit {
    errorMessage = '';

    contextmenu = false;
    contextmenuX = 0;
    contextmenuY = 0;
    contextMenuForGeocache: MyGeocache;
    innerWidth: any;
    innerHeight: any;

    constructor(...) { }

    ngOnInit() {
        // for determining where the put the context menu -- on the screen ;-) 
        this.innerWidth = window.innerWidth;
        this.innerHeight = window.innerHeight;
        ...
        }
    }

    showMenuOptions() {
        return 'Delete;Navigate;Edit;';
    }
    onrightClick(event, geocache: MyGeocache ) {
        this.contextmenuX = event.clientX - 100;
        this.contextmenuY = event.clientY;
        this.contextmenu = true;
        const menuHeight = this.showMenuOptions().split(';').length;
        const maxY = this.innerHeight - ( menuHeight * 30);
        if ( this.contextmenuY > maxY ) {
            this.contextmenuY = maxY;
        }
    }
    // disables the menu
    disableContextMenu() {
        this.contextmenu = false;
    }

    handleMenuSelection( menuselection: string) {
        if ( menuselection === 'Delete') {
            ...
        } else if ( menuselection === 'Navigate') {
            ...
        }
    }
}

contextmenu.component.html: Upon clicking a menu item it will be propagated to the parent to handle the selection.

<div class="contextmenu" [ngStyle]="{'left.px': x, 'top.px': y}">
  <ul class="list-group">
    <li class="list-group-item" *ngFor="let menuItem of theMenuItems">
      <span (click)="outputSelectedMenuItem( menuItem)">{{ menuItem }}</span>
    </li>
  </ul>
</div>

contextmenu.component.ts:

@Component({
    selector: 'app-contextmenu',
    templateUrl: './contextmenu.component.html',
    styleUrls: ['./contextmenu.component.css']
})
export class ContextmenuComponent implements OnInit {
    constructor() { }
    @Input() x = 0;
    @Input() y = 0;
    @Input() menuitems = '';
    theMenuItems = [];
    @Output() menuItemSelected = new EventEmitter();

    ngOnInit() {
        // Build the menu items
        this.theMenuItems = this.menuitems.split(';');
    }

    outputSelectedMenuItem( menuitem: string) {
        this.menuItemSelected.emit(menuitem);
    }
}

Comments

0

I have created a custom context menu with component any one can take an idea from it can build its own.

here is link

https://github.com/ieammac/angular-4-custom-context-menu

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.