0

I want to send a message to content.js from background.js when the user navigates on the page or reloads. Therefore I am using chrome.tabs.onUpdated.addListener function.

To check if my user is navigating on my page I use changeInfo.url and check if he is on that page. The problem is that whenever I use it in an if statement, the sendMessage function is not called and therefore, the listener in the content.js is not calling the function to update the DOM (updateTweets).

background.js

 chrome.tabs.onUpdated.addListener(function (tabId, changeInfo, tab) {
    chrome.storage.sync.get(["nickname", "stringInNickname", "username", "keyWords"], function (data) {
        if (changeInfo.url !== undefined && changeInfo.url.includes("somewebsite.com/page")) {
            chrome.tabs.sendMessage(tabId, data);
        }
    });
});

content.js

function setEventListeners() {
    chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
        data.unwantedNicknames = request.nickname.split(",").filter((val) => val != "");
        data.unwantedStringInNickname = request.stringInNickname.split(",").filter((val) => val != "");
        data.unwantedUsernames = request.username.split(",").filter((val) => val != "");
        data.unwantedKeyWords = request.keyWords.split(",").filter((val) => val != "");
        updateTweets();
    });
}

manifest.js

{
    "manifest_version": 2,
    "name": "extension",
    "version": "1.0",
    "content_scripts": [
        {
            "matches": ["*://*.somewebsite/page/*"],
            "js": ["./content.js"]
        }
    ],
    "permissions": ["storage", "tabs"],
    "browser_action": {
        "default_icon": "popup16.png",
        "default_popup": "panel/panel.html",
        "default_title": "My popup!"
    },
    "background": {
        "scripts": ["background.js"]
    }
}

I tried working around the problem and setting a timeout function for both updateTweets() and sendMessage() and it worked. I don't understand why the sendMessage is not being called. Previously it worked without any if statements, I even tried with changeInfo.status === "complete" and it worked. Does it have to do something with the callbacks?

Even if I just do if(changeInfo.url), something that I saw in another stack questions, the sendMessage is not called. But if I have some conosle logs in the if statement where sendMessage is they get logged in the console but sendMessage isn't called.

Also, chageInfo doesn't always return url in the object, maybe that's the problem, but I use the if statement to check if it is defined.

I could solve it with changeInfo.status and make a few unneeded calls of the updateTweets function, but I wan't to make it as right as possible. I'm pretty much struggling with this one the whole day.

I don't know why it is not working as expected

Filip
  • 183
  • 9
  • I don't see one of the most important things in an extension, manifest.json, so I guess it has the wrong `matches` and the content script isn't actually injected. Your first step should be assessing what really happens which you can reliably do in devtools - for the [background script](https://stackoverflow.com/a/10258029) and for the content script in the tab itself (open devtools, then `sources` panel, then `content scripts` sub-panel). Set a breakpoint in the listener and see what happens when it triggers. – wOxxOm Nov 25 '20 at 19:26
  • I just added the manifest.json to the post. When I debug step by step the code works as I want to and it sends the message to content.js and the dom is updated. I tried different tests and situations and it works. But when i'm not debugging it still doesn't send the message to content. It enters in the if statement and won't call sendMessage. I really can't understand why it behaves like that. – Filip Nov 25 '20 at 20:41
  • 1
    Looks like my guess about `matches` is correct assuming `somewebsite.com` is a Single-Page Application which uses programmatic navigation. So, if you open somewebsite.com first then the content script won't be injected on subsequently navigated pages. To fix this, inject on the entire site e.g. `*://somewebsite.com/*` – wOxxOm Nov 25 '20 at 20:45
  • Thanks for your comment, but it doesn't work like this. I changed it as you told me but still the same problem. Specifically, it was like this before `"matches": ["*://*.time.mk/twitter/*"],` , after I changed it it's like this `"matches": ["*://*.time.mk/*"],`. I don't know if the type of website changes something.... – Filip Nov 25 '20 at 21:29
  • 1
    Assuming you've reloaded the extension on chrome://extensions page and the tab itself, another reason could be that by default the scripts run only after DOMContentLoaded so try using [document_start](https://developer.chrome.com/extensions/content_scripts#run_time). – wOxxOm Nov 25 '20 at 23:12
  • I added document_start but it doesn't work. One thing I noticed is that on `changeInfo.url.includes("somewebsite.com/page")`, sometimes I get an error saying "Cannot read property 'includes' of undefined". But even when having this error, the if statement is true and it won't call sendMessage. Should I try and find an alternative to call sendMessage when the page is reloaded/navigated? – Filip Nov 26 '20 at 10:07
  • The `if` line should be moved outside of chrome.storage.sync.get so the condition is verified before calling it. – wOxxOm Nov 26 '20 at 10:32
  • 1
    I tried that but it still doesn't work. The only thing that I tried and it works is to put the sendMessage function in a timeout `setTimeout(() => chrome.tabs.sendMessage(tabId, data), 1000);`. Note that If I change the timeout time to less than 1 second it doesn't work. I just don't understand why this is happening. It will take too much time for the changes to become visible, so this is not an option to leave the timeout. Why is this happneing? How can I resolve it? – Filip Nov 26 '20 at 10:40
  • are you calling setEventListeners() anywhere? Maybe redundant as wrapper... – ned Aug 21 '21 at 17:12

1 Answers1

0

For me, setting a timeout time from 1 to 1000 works. This is very strange.

I check the value of changeInfo.status === "complete."

If the status is completed, then I use chrome.tabs.sendMessage() to send a message to contentScript.js.

This won't work unless I wrap the chrome.tabs.sendMessage() code inside setTimeout(() => {}, time) just like your only working solution.

espc
  • 57
  • 8