PerfectMemory / ngx-contextmenu

A context menu component for Angular
https://perfectmemory.github.io/ngx-contextmenu
MIT License
42 stars 12 forks source link

Example for ContextMenuService.show() #8

Closed anweihe closed 2 years ago

anweihe commented 2 years ago

Describe the bug Documentation for how to use the ContextMenuService.show() function is missing. I can't get this to work with the new version. Coming from version 6.

To Reproduce Try to implement the function.

Expected behavior The documentation for this function is existing.

sroucheray commented 2 years ago

Hi @anweihe ,

That's a good one. Thanks for pointing it out. When I forked the project everything was literally a public API. So one of the task I assign myself was to make it clearer what was public from what was private. Then coming to this ContextMenuService. IMO using this service is an advanced use case and I thought maybe it was only for edge cases. I was not able to identify myself those edge cases and thus did not want to completely privatize the service. So the trade off was to not document it. I told myself that for the newcomers, they won't see any service and won't use it, everything were fine. But for previous users they might want to find where the service went and look into the code or ask for it. Here you are :)

Could you take a minute to explain your use cases with the service ContextMenuService that you cannot achieve otherwise ?

Thanks by advance !

anweihe commented 2 years ago

Hi @sroucheray, sure! My use case may be a bit special. I'm using the library with Ionic for desktop and mobile. On desktop everything works as usual. On Android, the context menu is opened via long press. But on iOS I want to open it on a normal tap, and for this behavior I need the show() function on the click event. I figured now out how to make this work. The context-menu itself is registered as a ViewChild and passed as the first parameter. Here is my click event handler:

public onClick($event: MouseEvent, item: any): void {
    if (this.platform.is('desktop')) { return; }

    this.contextMenuService.show(
        this.eventMenu, // Context Menu ViewChild
        {x: $event.x, y: $event.y, value: item},
    );
  }
sroucheray commented 2 years ago

I see, I guess you want to do that because the contextmenu event is not supported by iOS yet ? image https://bugs.webkit.org/show_bug.cgi?id=213953

Would you see a generic way of workaround this limitation built in this library, and if yes, how would you see it ?

timonkrebs commented 2 years ago

We also need to do that because the contextmenu event is not supported by iOS yet.

sroucheray commented 2 years ago

I think there might be another way. The ContextMenuDirective directive exposes an onContextMenu method which is called by the contextmenu host listener. This method is documented as internal but I could make it public (or even give it a more appropriate name as open). It would require minor changes in the library. Then you could do something like :

<div
  #ngxContextMenu="ngxContextMenu"
  (click)="ngxContextMenu.onContextMenu($event)"
></div>

<!-- or in case I rename the method -->

<div
  #ngxContextMenu="ngxContextMenu"
  (click)="ngxContextMenu.open(event)"
></div>

The other change I would need to do is to add an exportAs property to the directive decorator.

Those changes are very generic and can be used with other events, like key bindings:

<div
  #ngxContextMenu="ngxContextMenu"
  tabindex="0"
  (keydown.enter)="ngxContextMenu.open(event)"
></div>

What do you think @anweihe and @timonkrebs ?

sroucheray commented 2 years ago

Wrote specifications for the implementation https://github.com/PerfectMemory/ngx-contextmenu/issues/10

Slavrix commented 2 years ago

https://github.com/isaacplmann/ngx-contextmenu#context-menu-in-a-different-component The contextMenuService was also used here for opening a context menu from a different component.

  onContextMenu($event: MouseEvent, value) {
    this.contextMenuService.show(
    this.contextMenuTemplate, 
    {
      x: $event.clientX,
      y: $event.clientY,
      value: value
    })
    $event.preventDefault();
    $event.stopPropagation();
  }

This works with opening the context menu.

you can also just pass the whole template from the parent in and that works too ofc. adding to the child, where @Input() contextMenuTemplate is the whole <context-menu>

[contextMenu]="contextMenuTemplate"
[contextMenuValue]="event"
sroucheray commented 2 years ago

I implemented open and close methods on the ContextMenuDirective. I consider that it closes this issue. If you think this is not the case, please open another issue.