iVis-at-Bilkent / cytoscape.js-context-menus

A Cytoscape.js extension to provide context menu around elements and core instance
MIT License
86 stars 41 forks source link

How can I check if a particular submenu item already exists? #67

Closed lilfrootyloops closed 2 years ago

lilfrootyloops commented 2 years ago

Description: I've implemented functionality to dynamically add items to a submenu depending on the kind of node that has been selected using appendMenuItems(). However, when I open the context menu immediately again, even for a completely different node, I am running into the following runtime error:

Error: There is already an element with id=swagSauce in the context menu

I understand why I would see this error if I were to open the context menu for the same node back-to-back, because appendMenuItems() is trying to create submenu items that already exist by running again with the same parameters from earlier; however, I am not sure why this is happening when I try to open the context menu for a different node. I think what I need to do is wrap appendMenuItems() inside of a conditional statement so that it will only run if one of the parameters being passed into appendMenuItems() doesn't already exist; however, I am not sure how I can check for that.

Is it possible to see whether there is already an element with the same id in the context menu? If so, I'd really appreciate it if someone could explain how I can do that. I've included my code below:

Code:

let submenuItems = [];

function Object(x, y) {
    this.id = x;
    this.content = `${x}: ${y}`;
    this.tooltipText = `${x}: ${y}`;
    this.onClickFunction = () => {
        testFunction(x, y)
    };
};

const options = {
    evtType: 'cxttap',
    menuItems: [
        {
            id: 'one',
            content: 'This is the first option in the menu',
            selector: 'node',
            onClickFunction(evt) {
                genericFunctionName(evt, 'one')
            },
        },
        {
            id: 'two',
            content: 'This is the second option in the menu',
            selector: 'node',
            onClickFunction(evt) {
                genericFunctionName(evt, 'two')
            },
        },
        {
            id: 'three',
            content: 'This is the third option in the menu',
            selector: 'node',
            submenu: [],
        },
    ],
};

let instance = cyRef.current.contextMenus(options);

cyRef.current.on('cxttap', "node", function(evt) {
    for (const variable in evt.target.data('properties')) {
        submenuItems.push(new Object(variable, evt.target.data('properties')[variable]));
    }

    instance.appendMenuItems(submenuItems, "three");
}

Additional Context I am using Cytoscape Context Menus v4.1.0.

canbax commented 2 years ago

Actually, you can check it manually on your own since you are the one who is calling the appendMenuItems function with certain IDs.

But I should admit that an API method like getMenu() might have been useful here.

lilfrootyloops commented 2 years ago

Could you please provide an example of how I can check it on my own? As I mentioned in the original post, I am not sure how I would be able to do that. Would it be something like if (x exists), {then don't run y function}? I'm not sure what variable or value I'd have to substitute for x though in order to specifically tell that condition to check for a particular menu item ID. Would it be instance.[insert something] or something like that? When I console.log instance, I don't see any values that would indicate what the existing menu item IDs are.

I understand that I can add menu items manually with specific IDs using appendMenuItems, but working with specific IDs to perform actions only seems possible with appendMenuItems and Cytoscape Context Menus library's other pre-built functions (e.g., enableMenuItem, disableMenuItem, removeMenuItem, showMenuItem, etc.). My goal is to programmatically check for these IDs and not do it manually. As you mentioned, there isn't a pre-built method to retrieve menu items, so I would really appreciate any guidance on how I can return the menu items and check if a menu item with a specific ID already exists.

canbax commented 2 years ago

Hi @lilfrootyloops

You can keep an object like let currentMenuItems = {'one': true, 'two': true, 'three': true}.

Then when you try to add a new menu item, you can check if it is already added.

function addNewItem(newItemID) {

  if (currentMenuItems[newItemID]) {
    return;
  }
  currentMenuItems[newItemID] = true;
  // use API to add menu item
}