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);
}
}