PerfectMemory / ngx-contextmenu

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

Trouble Opening Context Menu in Separate Component via Service #33

Open LeeWhite187 opened 10 months ago

LeeWhite187 commented 10 months ago

Pretty sure this isn't a bug. Just my lack of understanding how to use this library.

I have several context menus that I've built. And, I get them to display by calling the ContextMenuService.open method, with the appropriate template directive. That all works fine, and is based on the template ref and ViewChild go-by's that I've followed.

But. I want to move these context menu blocks into their own components, so they're not jammed at the bottom of my layout file and still be able to open the appropriate menu programmatically (via the ContextMenuService.open method).

Each of the menu implementation components I created, extends ContextMenuComponent, which I was hoping would make things work. But, I still can't pass one into the ContextMenuService.open method. I get this compile-time error message:

Argument of type 'typeof PanelCtxmenuComponent' is not assignable to parameter of type 'ContextMenuComponent'. Type 'typeof PanelCtxmenuComponent' is missing the following properties from type 'ContextMenuComponent': #private, overlay, scrollStrategy, contextMenuOverlaysService, and 18 more.ts(2345)

Is there a trick that I'm missing? I figured it was a similar pattern to dynamically adding components, by passing the desired type to a handling service. But, I seem to be hitting a polymorphism issue.

Here's an example of the component declaration of one of my menus:

` import { Component } from '@angular/core'; import { ContextMenuComponent } from '@perfectmemory/ngx-contextmenu';

@Component({
  selector: 'panel-ctxmenu',
  standalone: true,
  imports: [],
  templateUrl: './panel-ctxmenu.component.html',
  styleUrl: './panel-ctxmenu.component.scss'
})
export class PanelCtxmenuComponent extends ContextMenuComponent<unknown> { }

`

I can't imagine organizing menu implementations into components is uncommon. But, is there a guide on how to do this?

Thanks,

Lee

sroucheray commented 10 months ago

Hi @LeeWhite187,

Interesting question. I think in most cases, you should prefer composition to inheritance. You could keep your PanelCtxmenuComponent but instead of extending ContextMenuComponent you could create one in its template <context-menu #contextMenu></context-menu> and have a public view child to reference it

  @ViewChild('contextMenu', { static: true })
  public contextMenu?: ContextMenuComponent;

Then in any component that would need the context menu you can pass it as an input and open it with the service:

  @Input()
  public panelContextMenu?: PanelCtxmenuComponent<T>;

  @HostListener('contextmenu', ['$event'])
  public onContextMenu(event: MouseEvent): void {
    this.contextMenuService.show({
      contextMenu: this.panelContextMenu?.contextMenu
    });

    event.preventDefault();
    event.stopPropagation();
  }
...

Sadly, there is no advanced guide for such case as of today.