5

I'm trying to work on a chrome extension and am trying to clean up some of my code by relying on the sendMessage. However the callback function activates before the page has finished loading so in the case of a new tab, nobody receives and in the case of an existing tab the page that is being moved from is getting the message (but that isn't what I want). I've looked for other people asking about that problem with new tabs and there wasn't a clear answer, the best suggestion I've seen is to create a global variable and create a listener for tab loads and compare it against this global variable.

So the question is, is there a way to wait in the callback function until the page has loaded, or do I create an array of JS objects that contain the tab I'm waiting on and the information I want to send to that tab.

For reference here is the relevant code in the background javascript file.

   chrome.tabs.sendMessage(tab.id, {info: "info"}, function(response)  
   {
     //This line isn't used when I am navigating without changing tabs
     chrome.tabs.create({url: response.info.linkUrl}, function(tab1)
     {
       chrome.tabs.update(tab1.id, {url: response.info.linkUrl}, function(tab2)
       {
         chrome.tabs.sendMessage(tab2.id, {info: "More Info"});
       });
     });
   });

Otherwise I am able to confirm that all of my tab side code works, once my sendMessage was delayed enough for me to see that with my own eyes. My code is able to consistently make it past validation on the page being navigated away from, confirmed by checking document.url.

pafk
  • 107
  • 2
  • 12

2 Answers2

4

You can try injecting a second content script instead of a message. It will execute in the same context as your other script.

Something along the lines of

chrome.tabs.executeScript(tab2.id, 
  {code: 'showInfo("More Info);', runAt: 'document_idle'}
);

where showInfo does the same as your message handler.

It's a bit of a hack and I'm not 100% sure the load order will be correct.

Other possible solutions are more complex.

For example, you can make the content script report back that it is ready and have a handler for that, for instance you can register a listener for onMessage in the background that waits for a message from that specific tab.id, sends "More Info" and then deregisters or disables itself.

Or, you could potentially switch to programmatic injection of your content script, which would let you control load order.

Community
  • 1
  • 1
Xan
  • 74,770
  • 16
  • 179
  • 206
  • 1
    Oddly enough executeScript acted on the new page rather than the old page and it works for both new tab and current tab. Thanks. – pafk Apr 07 '14 at 17:41
0

Since runAt: 'document_idle' didn't work for me, I ended up using chrome.webNavigation.

The following will be fired when a tab has finished its loading. You can use details.tabId for filtering the chrome.tabs.update-ed tab.

chrome.webNavigation.onCompleted.addListener(function(details) {
  if (details.frameId === 0) {
    console.log("webNavigation.onCompleted:", details.tabId)
  }
});

Note that you need to add the permission on your manifest.

{
  ..
  "permissions": [
    "webNavigation"
  ],
  ..
}