isaacplmann / ngx-contextmenu

An Angular component to show a context menu on an arbitrary component
MIT License
248 stars 91 forks source link

Open context menu on mouseup #141

Closed averude closed 6 years ago

averude commented 6 years ago

Hello. I've faced an issue of the 'mouseup' event. For example, let's take a simple code:

...
class SomeComponent {
  @ViewChild(ContextMenuComponent)
  public basicMenu: ContextMenuComponent;
  ...
  @HostListener('mouseup', ['$event'])
  onMouseUp(event: MouseEvent) {
    this.onContextMenu(event, null);
  }
  ...
  onContextMenu($event: MouseEvent, item: any): void {
    this.contextMenuService.show.next({
      contextMenu: this.basicMenu,
      event: $event,
      item: item,
    });
    $event.preventDefault();
    $event.stopPropagation();
  }
}

It doesn't matter how to call onContextMenu() (from template or component's code). The point is that custom event handling works well with other events except this one, and I'm curious if this kind of behavior is correct. The further experiments showed that when this event is fired, the context menu opens and closes immediately. It could be easily checked by calling some logging method on (open) and (close) events of context menu:

<context-menu (open)="logOpened()" 
              (close)="logClosed()" 
              #basicMenu>
  <ng-template contextMenuItem>Hello</ng-template>
</context-menu>

P.S. Showing context menu on mouseup event is very useful thing on handling 'drag-to-select' mouse operations.

isaacplmann commented 6 years ago

I bet the problem is that you are stopping the propagation of the mouseup event, but the mousedown and click events are still going through to the document which is immediately closing the context menu. You could try wrapping this.contextMenuService.show in a setTimeout to hack around the problem. That way the click event on the document would be handled first and then you would open the context menu.

Let me know if that works for you.

averude commented 6 years ago

I bet the problem is that you are stopping the propagation of the mouseup event, but the mousedown and click events are still going through to the document which is immediately closing the context menu. You could try wrapping this.contextMenuService.show in a setTimeout to hack around the problem. That way the click event on the document would be handled first and then you would open the context menu.

Let me know if that works for you.

Hello Isaac, thanks for the quick reply. You were absolutely right, wrapping this.contextMenuService.show in setTimeout successfully solved the problem.

P.S .Just in case someone else has to deal with it, here is the result code:

...
class SomeComponent {
  @ViewChild(ContextMenuComponent)
  public basicMenu: ContextMenuComponent;
  ...
  @HostListener('mouseup', ['$event'])
  onMouseUp(event: MouseEvent) {
    this.onContextMenu(event, null);
  }
  ...
  onContextMenu($event: MouseEvent, item: any): void {
    setTimeout(() => {
            this.contextMenuService.show.next({
            contextMenu: this.basicMenu,
            event: $event,
            item: item,
            });
            $event.preventDefault();
            $event.stopPropagation();
    }, 10);
  }
}