9

A while ago I could save ID of the created item for the context menu in Google Chrome Extensions:

background.js:

var myItem;

if (myItem !== "MyItem") {
    myItem = chrome.contextMenus.create({
        title: "My item",
        id: 'MyItem',
        contexts: ["page"]
    });
}

But now when I open Chrome first it says:

Unchecked runtime.lastError while running contextMenus.create: Cannot create item with duplicate id MyItem

(from debug console)

So it doesn't remember my variable "myItem" (its data) anymore when I close Chrome. It only remembers while Chrome is opened.

So now should I use chrome.storage.local.get or set to save ID of my Context Menu Items?

Update:

The problem was a "persistent": false in manifest for background:

   "background": {
      "scripts": [ "background.js" ]
   },

Removed it & now it works normally [Solved]

user25
  • 2,873
  • 2
  • 30
  • 66

3 Answers3

15

local storage is definitely an option.

Though another option is to removeAll before creating:-

chrome.contextMenus.removeAll(function() {
  chrome.contextMenus.create({
    title: "My item",
    id: 'MyItem',
    contexts: ["page"]
  });
});

I used this way when I had dynamic subMenus, etc and found it much easier to recreate the whole menu than to try to determine which options should be added/removed.

BenG
  • 14,826
  • 5
  • 45
  • 60
4

You should only create menu items in chrome.runtime.onInstalled event.

See also: https://developer.chrome.com/extensions/background_pages#listeners

BlackGlory
  • 3,866
  • 2
  • 15
  • 21
  • what?! xD this event is called only once (during extension installing), on the next browser start you won't see any menu items – user25 Dec 16 '18 at 18:42
  • This is true, but the menu items only need to be created during the first installation, because Chrome will remember the menu items. If you try it at least once, you'll know that menu items will still exist even if you restart Chrome. Chrome will temporarily close non-persistent extensions to reduce the extra performance loss caused by the extensions. – BlackGlory Dec 22 '18 at 19:17
  • When non-persistent extensions are active again, they will re-run background.js, which is why you get "Cannot create item with duplicate id MyItem", because the menu items were not being deleted. – BlackGlory Dec 22 '18 at 19:17
  • Unless you disable or remove extensions, menu items are always there. If you need to dynamically update menu items, update or recreate menu items directly when your needed, just do not writing the code for creating menu items in background.js re-run scope. – BlackGlory Dec 22 '18 at 19:18
  • I solved my problem a long time ago (this question is quite old). Just look at the next extension. It dynamically creates context menus, it works great. Users can disable/enable specific context menus using Extension's settings page https://chrome.google.com/webstore/detail/potplayer-youtube-shortcu/cfdpeaefecdlkdlgdpjjllmhlnckcodp?hl=ru – user25 Dec 22 '18 at 20:12
  • I tried to run 'Control + R' being on the background page which actually aroused the issue. Otherwise, it's working fine. But can't move the context menu on `onInstalled` event, as the context menu is generated with document URL patterns that are pulled from the remote server. – ssi-anik Mar 25 '21 at 02:19
2

Do note that it's always safe to remove-then-add a context menu item:

// Or removeAll and create all
chrome.contextMenus.remove('MyItem', function() {
  chrome.contextMenus.create({
    title: "My item",
    id: 'MyItem',
    contexts: ["page"]
  });
});

There is no need to store the result of this operation; and you don't need to invoke it often as chrome persists the context menu between restarts.

Having a listener to chrome.runtime.onInstalled and doing this operation there will work great except for one corner case.

Xan
  • 74,770
  • 16
  • 179
  • 206
  • 1
    I found out why it started to show this error - I set `"persistent": false` for background in my manifest once. _There is no need to store the result_ - yes, you right, but in my case my items are optional (users can enable/disable it in extension settings) and there some conditions when one item should not be displayed if second is enabled for e.g.: `if (... && myItem2 != "MyItem2") { ...create...}` – user25 May 03 '16 at 09:44
  • Closing the browser would still wipe your background's state, persistent or not. You should be using `chrome.storage` to store user preferences, indeed. But to begin with, read carefully the [Event pages](https://developer.chrome.com/extensions/event_pages) docs. – Xan May 03 '16 at 09:45
  • _still wipe your background's state_ mb but when it's true there is no error after restarting the browser. Actually there is nothing to worry about when I see this error or no when debugging, the extension would be still working as I want (Chrome is not going to create many items in the context menu with the same id anyway). – user25 May 03 '16 at 10:27
  • _You should be using chrome.storage to store user preferences_ yeah of course, I'm using it & `chrome.runtime.sendMessage` in options.js and in bg.js items are created/reacreated on `chrome.runtime.onMessage.addListener`. And because items are recreated I still need to check if it's in the context menu using some variables in bg.js – user25 May 03 '16 at 10:27
  • There is no API to check existence of a context menu item (though perhaps you could rig `update` to catch errors). To make sure this code does not run more than once per browser start, put it in a `chrome.runtime.onStartup` listener. Migrating a background page to an event page is not always straightforward. – Xan May 03 '16 at 10:28
  • 1
    No, I removed `"persistent": false` and there is no error anymore, so I don't migrate bg to an event page. I don't rembember why I set it false (mb I was trying to solve some problems, but I definitely don't need it now). `There is no API to check existence of a context menu item` - anyway my conditions (if !item2... create) works good using simple variables like `var = var myItem1, myItem2...;` in bg to check – user25 May 03 '16 at 10:40