8

I'm trying to write a Google chrome extension that grabs the element in the page by its class name. The idea is to use the content script to grab these elements and pass the messages to the extensions and pop up. However, my content script always end up executing before the entire page is loaded so I can't grab the elements that I want. I try using window.loaded and document.loaded but it didn't work. I also tried wait an interval but the script always ended up executing at the exact same stop point.

// my content script

if (document.readyState == "complete"){
    var board_name_arr = [];
    var node = document.getElementsByClassName('Board');

    for (var i = 0; i < node.length; ++i){
        var board_name = node[i].getElementsByClassName('boardName')[0].textContent;
        board_name_arr[i] = board_name;
    }

    if (Object.keys(board_name_arr).length){
        alert("found board");
    }
}

Is there a way to force it to run after ? Or should I not be using content script approach?

Irene Yeh
  • 85
  • 1
  • 1
  • 3
  • Probably duplicate with this one: http://stackoverflow.com/questions/13917047/how-to-get-a-content-script-to-load-after-a-pages-javascript-has-executed – Dayton Wang Jan 28 '15 at 21:42

4 Answers4

10

Probably the page loads its content dynamically though AJAX, so the elements you want to find may be still not loaded when the document state is ready. Even if some part of content is loaded on start, more content may come later. To solve this issue correctly I'd recommend you the MutationObserver techniques. I used it in my Chrome extension to inject the 'Favorite' button to each Facebook post and it worked perfectly.

See the code sample:

var obs = new MutationObserver(function (mutations, observer) {
    for (var i = 0; i < mutations[0].addedNodes.length; i++) {
        if (mutations[0].addedNodes[i].nodeType == 1) {
            $(mutations[0].addedNodes[i]).find(".userContentWrapper").each(function () {
                injectFBMButton($(this));
            });
        }
    }
    injectMainButton();
});
obs.observe(document.body, { childList: true, subtree: true, attributes: false, characterData: false });
Alexander Dayan
  • 2,846
  • 1
  • 17
  • 30
4

Without jQuery you can do this defining a callback function on the page load event. You can do it this way :

var loadfunction = window.onload;
window.onload = function(event){
    //enter here the action you want to do once loaded

    if(loadfunction) loadfunction(event);
}

Or this way :

window.addEventListener("load", function load(event){
    window.removeEventListener("load", load, false); //remove listener, no longer needed
    //enter here the action you want to do once loaded 
},false);
NeoPix
  • 433
  • 5
  • 14
  • This works! I used the first one but I don't really understand the callback function. Does it wait for all pages to load and then call the function again if it's not? – Irene Yeh Jan 29 '15 at 05:25
  • `window.onload` is an event, it mean that it's called once the page is loaded. You can get more informations on events here http://www.quirksmode.org/js/introevents.html or wherever on the internet. – NeoPix Jan 29 '15 at 07:59
  • Suggest looking into run_at option of content_scripts. Works for your problem, https://developer.chrome.com/extensions/content_scripts#run_time – Satya Kalluri Oct 13 '20 at 13:05
1

I know, this question was posted way too long. Nevertheless, hoping it would be helpful for anyone scouting like me.

Chrome Extension's ContentScript have an option called run_at with options: document_start , document_idle & document_end. Documentation: https://developer.chrome.com/extensions/content_scripts#run_time

.
.
.
  "content_scripts": [
    {
      "js": ["PATH_TO_YOUR_SCRIPT.JS"],
      "run_at": "document_end"
    }
  ]
.
.
.

is exactly what you needed (is the partial content of manifest.json file.

Satya Kalluri
  • 5,148
  • 4
  • 28
  • 37
-5

Try to use Jquery

$(document).ready(function(){ //your code here });

http://learn.jquery.com/using-jquery-core/document-ready/

JMV
  • 1
  • 1