isaacplmann / ngx-contextmenu

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

[Dynamic actions] execute not fired #98

Closed namnn closed 6 years ago

namnn commented 6 years ago

Hi,

We were using the dynamic action context-menu. All the input binding like visible, enabled, divider work fine, but not the output execute.

When using ngFor for the actions, it does actually fires triggerExecute, but the function I bind never get called.

Fyi, I added an independent contextMenuItem (Test) and it triggers doAlert, unlike those inside the loop.

Please have a look. Thanks in advance.

Here is how we are using it:


<ul>
  <li *ngFor="let item of items;"
      [contextMenu]="contextMenu"
      [contextMenuSubject]="item">........</li>
</ul>
<context-menu #contextMenu>
  <ng-template
    *ngFor="let action of contextMenuActions"
    contextMenuItem let-item
    [visible]="action.visible" [enabled]="action.enabled"
    [divider]="action.divider" (execute)="doAlert('hello')"
  >
    {{action.text(item)}}
  </ng-template>
  <ng-template contextMenuItem (execute)="doAlert('hello')">
    Test
  </ng-template>
</context-menu>
isaacplmann commented 6 years ago

I don't see anything wrong with your template code. What does the ts file look like?

namnn commented 6 years ago

This is my component's ts


get contextMenuActions(): IMenuItem<IDummyEntry>[] {
    return transformContextMenuActions([
      {
        execute: entry => {
          console.log(entry);
        },
        text: () => {
          return 'Test 1';
        },
        visible: () => true
      },
      {
        divider: true,
        visible: entry => true
      },
      {
        execute: entry => {
          console.log('hello world')
        },
        text: entry => 'Test 2',
        visible: entry => true
      }
    ]);
  }

doAlert(message): void {
    console.log(message);
  }
....
function transformContextMenuActions<T = {}>(actions: Partial<IMenuItem<T>>[]): IMenuItem<T>[] {
  const defaultMenuItem = {
    execute: () => {},
    divider: false,
    enabled: () => true,
    text: () => '',
    visible: () => true
  };
  return map(actions, (action: IMenuItem<T>) => ({ ...defaultMenuItem, ...action }));
}
namnn commented 6 years ago

I find that after reaching this statement, the execute function doesn't really get bubbled up to the component, but rather trigger close the contextMenu only


subscriptions.add(contextMenuContent.instance.execute.asObservable()
            .subscribe(function (executeEvent) { return _this.closeAllContextMenus(__assign({ eventType: 'execute' }, executeEvent));
sherlock1982 commented 6 years ago

I had similar issue with execute not fired. Needed to call "setTimeout" after contextMenuActions was set for context menu. Try if it's your case. Though I must say it wasn't an issue in angular2-contextmenu.

namnn commented 6 years ago

@sherlock1982 thanks for sharing your experience, it really helped me out.

I change from using get function to binding to public attribute in ngOnInit and it works.