Zip
Zip

Reputation: 5592

Why can't my content script use already injected script?

For my Chrome extension, I inject a Javascript file and a CSS file that are needed for the modal to load up by using content.js. Injection is successful and I see those two files in the DOM.

And then I send a message to the background.js to do some stuff and this works too because I receive the message back from there. But my modal fails to load because it seems that it cannot use the injected Javascript file.

Let's say I have a function that inject the files into DOM. Let's call it inject(). I call this function at the start of the content.js file and they are injected successfully. But when I get back message from background.js and try to load the modal, it fails.

If I again try to call inject() function inside chrome.runtime.sendMessage function, the modal successful loads up.

In content.js I have the following code. I send a message to the background script whenever user click a link on the current page.

chrome.runtime.sendMessage(link,function(response){
     inject(); //Now the modal loads. But if I remove this, the modal fails to load.    
     loadModalFunction(response);
});

My question then is if I had already injected modal.js and modal.css as soon as the page has loaded, why do I need to inject the files again to load the modal? My extension loads the modal whenever a user click a link on a page. So my concern is that if I have to inject the two files into the DOM whenever a user clicks something, it would make the page slow.

Update with more code:

In content.js:

function injectStuffs(){
    var jquery = chrome.extension.getURL("jquery-1.11.3.min.js");
    var script = document.createElement('script');
    script.type = 'text/javascript';
    script.src = jquery;
    $("head").append(script);

    var modaljs = chrome.extension.getURL("modal.js");
    var script = document.createElement('script');
    script.type = 'text/javascript';
    script.src = modaljs;
    $("head").append(script);

    var link = document.createElement("link");
    link.href = chrome.extension.getURL("modal.css");
    link.type = "text/css";
    link.rel = "stylesheet";
    $("head").append(link); 
}

injectStuffs() //Inject the scripts into ```DOM```

$(document).on('click', '.readmore a', function(event) {
    event.preventDefault();
    var link = $(this).attr('href');

    chrome.runtime.sendMessage(link,function(response){
        injectStuffs() //I need to inject here again to load the modal up. Why?
        loadModal(response);
    });
});

Upvotes: 2

Views: 1254

Answers (1)

Ryan Tarpine
Ryan Tarpine

Reputation: 791

I'm actually surprised that calling injectStuffs() a second time works! I believe the problem is caused by the "isolated world" that your content script is running in:

Content scripts execute in a special environment called an isolated world. They have access to the DOM of the page they are injected into, but not to any JavaScript variables or functions created by the page. It looks to each content script as if there is no other JavaScript executing on the page it is running on. [reference]

When you list JavaScript files in the js property of a content script in your manifest, all those files are considered to be part of the content script, so each of the files can see the functions/variables defined in the others (but not in the page).

In contrast, when you inject JavaScript files by writing <script> elements to the DOM, those files are considered to be part of the page, so your content script can't see the functions/variables defined in them.

So in your situation, content.js is in your content script, but jquery-1.11.3.min.js and modal.js are in the page. That's why content.js can't call loadModal().

You probably want to add jquery-1.11.3.min.js and modal.js to your content script in the manifest. But if you really need to decide at runtime whether to load the JavaScript files, then see the docs for programmatic injection.

Upvotes: 1

Related Questions