3

I'm injecting all my js code to front page, but it needs pictures for ui and stuff, that can be imported only with the help of chrome.extension.getUrl and can be called only from content-script, so I've found tons of advices how to pass data to content page, and nothing of about how pass data back, is it possible at all?

My code now looks like this:

my js code, that will be injected with other code:

var Content = {}; $(document).contentReady = function(content) { Content = content; $(document).ready(function () {/*cool stuff here, that require content*/}); } var event = new CustomEvent('LoadContent'); window.dispatchEvent(event); 

content-script:

document.querySelector('head').appendChild(jsCode); window.addEventListener("LoadContent", function(evt) { var content = { data: "url(" + chrome.extension.getURL('content.smth') + ")" }; document.contentReady(content); }, false); 

And, obviously, I get document.contentReady is not a function But declaring function in document was the only(!) advice of about how to pass data back from content-script after about 2 hours of googling.

3
  • 1
    @Madara I disagree with the duplicate, but seeing as my reopen vote has a potential of immediate reopening, I would like to avoid attracting the wrath of a (fresh) diamond. My reasoning: your duplicate shows only one possible avenue of answering the question, and not how it's formulated: "how pass data back". There are other methods that are not coverable by the dupe target (injecting a method to window). This is a more general question and the dupe should be lifted. Your decision seems to base on an existing answer. Do you agree? Commented Nov 30, 2015 at 11:07
  • @Xan: Sure, go ahead and reopen it if you think my decision was wrong. Also, don't be afraid to incur my wrath. I appreciate any and all criticism to my decisions. Commented Nov 30, 2015 at 11:25
  • 1
    @MadaraUchiha I just thought that doing that without commenting would not be enough of a criticism. Commented Nov 30, 2015 at 12:29

3 Answers 3

3

Nothing stops you from making the CustomEvent-based communication bi-directional, and it can pass data with detail property:

// Page script window.addEventListener('RecieveContent', function(evt) { // do something cool with evt.detail }); var event = new CustomEvent('LoadContent'); window.dispatchEvent(event); // Content script window.addEventListener('LoadContent', function(evt) { content = /* ... */ var event = new CustomEvent('RecieveContent', {detail: content}); window.dispatchEvent(event); }); 

A more in-depth answer can be found here.

However, you should ask yourself whether you even need the page-level script to query for data, since you fully control when it's injected. You can use uni-directional approach after you make sure the code has executed:

// Page script window.addEventListener('RecieveContent', function(evt) { // do something cool with evt.detail }); // Content script jsCode.onload = function() { // This fires after the page script finishes executing content = /* ... */ var event = new CustomEvent('RecieveContent', {detail: content}); window.dispatchEvent(event); } document.querySelector('head').appendChild(jsCode); 
Sign up to request clarification or add additional context in comments.

1 Comment

yes, elegant and easy, thanks for answer, Xan! didn't know that I can do like that, too new at web-dev. I've looked over all of your answers that night, but events were passing to 'chome.whatever...', glad you took a look at this, thx!
1

You can pass JS data to the page by creating a new script tag. For example:

function injectScript(code) { var body = document.getElementsByTagName('body')[0]; var s = document.createElement('script'); s.innerHTML = code; body.appendChild(s); } injectScript('var foo = 2;'); 

So for your particular example, you should be able to do:

injectScript('document.contentReady({data: url(' + blahblah + '})'); 

Not pretty (what is when you're working with overwriting content scripts?) but it works.

1 Comment

well ok, looks pretty simple, but how can I find out, that the data has been received?
1

Content Scripts do not share window object with normal scripts on the page. Both of them work on different context.

In your case, you are registering an event listener on window and listening for the event on other context (window). Hence, your event listener will never be called.

However, there is one alternative approach I can see to communicate between content script and normal script is by using MutationObserver.

Idea

  1. Define a node with some Id under which you will create subnodes corresponding to an event.
  2. Register Mustation Observer in your script.
  3. From content script, add the nodes with data as data-* api.

Implementation Example

Content Script
var submitEvent = function(category, action, label) { var eventObserverPlaceholder = document.getElementById('events-observer-placeholder'), $eventEl = $('<span></span>').attr({ 'data-category': category, 'data-action': action, 'data-label': label }); eventObserverPlaceholder.appendChild($eventEl.get(0)); }; 

Normal Script for registering Mutation Observer:

RQ.Methods.addObserverForEvents = function(targetNode) { var observer = new MutationObserver(RQ.Methods.handleMutationList); // Notify me when a new child is added var observerConfig = { attributes: false, childList: true, characterData: false }; observer.observe(targetNode, observerConfig); return observer; }; RQ.mutationObserver = RQ.Methods.addObserverForEvents(document.getElementById('events-observer-placeholder')); 

Links

  1. https://davidwalsh.name/mutationobserver-api
  2. https://developer.mozilla.org/en/docs/Web/API/MutationObserver

Working Example:

I have used the same approach in Requestly Chrome Extension for submitting events to Google Analytics.

  1. Content Script: https://github.com/requestly/chrome-extension/blob/master/src/Shared/utils.js#L26
  2. Normal Script: https://github.com/requestly/web/blob/gh-pages/js/scripts/tracker.js#L35

3 Comments

While this is a more elegant solution, you can simply inject a <script> tag to the page and then access the execution content of the main page.
@gladsocc Advantage with this method is you can communicate between both content scripts and normal scripts using this approach. You just need two placeholders.
looks a bit confusing to me at first, but I'm going to try this one, seems like it's gonna work, thanks a lot for response!

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.