Zack Shapiro
Zack Shapiro

Reputation: 6998

Chrome Extension: Adding event listener not working after site loads

I'm building a Chrome Extension to add some shortcut functionality to a site I regularly work with. I've tried calling my addTypingListeners() to bind the div with 2 inputs that I've added to the title and subtitle of the edit page I'm working on. However, I never seem to get into the document.eventListener closure.

My Chrome Extension is run at document_idle so the content should be loaded by the time my additional code runs. How can I get these listeners to embed on the page?

Even when I don't call addTypingListeners(), I still see a and b log in the console

function addTypingListeners() {
    console.log('a')
    var meta = {}

    document.addEventListener("DOMContentLoaded",()=>{
        console.log('listeners added pre')
        bind(meta, document.getElementsByTagName('title'), "title");
        bind(meta, document.getElementsByTagName('subtitle'), "subtitle");

        setInterval(()=>{document.getElementsByTagName('h3')[0].innerText=meta.title});
        setInterval(()=>{
            console.log(meta)
            document.getElementsByTagName('h4')[0].innerText = meta.subtitle
        });

        console.log('listeners added')
    })

    console.log('b')
}

const start = async function() {
    // var location = window.location.toString()
    let slug = window.location.toString().split("/")[4]
    let url = `https://example.org/${slug}?as=json`

    const _ = await fetch(url)
        .then(res => res.text())
        .then(text => {
                let obj = JSON.parse(text);
                const { payload } = obj;

                // Container
                const root = document.getElementById('container');
                var clippyContainer = document.createElement('div');
                createShell(clippyContainer, name);
                root.appendChild(clippyContainer);

                // Inputs
                const title = document.getElementsByTagName('h3')[0];
                const subtitle = document.getElementsByTagName('h4')[0];

                var inputDiv = document.createElement('div');
                inputDiv.id = "input-div";
                const titleInput = document.createElement('input');
                titleInput.id = "title"
                titleInput.value = title.innerText;
                inputDiv.appendChild(titleInput);

                const breaker = document.createElement("br")
                inputDiv.appendChild(breaker);

                const subtitleInput = document.createElement('input');
                subtitleInput.id = "subtitle"
                subtitleInput.value = subtitle.innerText;
                inputDiv.appendChild(subtitleInput);
                clippyContainer.appendChild(inputDiv);

                inputDiv.appendChild(breaker);

                // addTypingListeners() // tried here, also doesn't work
        });
}

start()
    .then( (_) => { 
        console.log('hi')
        addTypingListeners() 
        console.log("done")
    })

Upvotes: 6

Views: 2253

Answers (3)

Burak Gök
Burak Gök

Reputation: 340

  1. The code you provided should be injected to the page as a content script (for details).
  2. According to the official documentation, the order of events while a page is loading:

    document_start > DOMContentLoaded > document_end > load > document_idle.

    The difference between load and DOMContentLoaded events is explained here as

    The load event is fired when the whole page has loaded, including all dependent resources such as stylesheets and images. This is in contrast to DOMContentLoaded, which is fired as soon as the page DOM has been loaded, without waiting for resources to finish loading.

    Thus, you should add the listeners without waiting for the DOMContentLoaded event, which will never fire.

Upvotes: 1

Tom Shaw
Tom Shaw

Reputation: 1712

This is literally all the coded need besides whatever your doing to the dom.

Background.js

let slug = window.location.toString().split("/")[4]
let url = `https://example.org/${slug}?as=json`

fetch(url).then(res => res.text()).then((data) => {
  chrome.tabs.sendMessage(tabId, {
    message: data
  });
})

Content.js

function addTypingListeners(data) {
  // Update page dom
}


chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
  if (request.message) {
    addTypingListeners(request.message);
  }
});

Upvotes: 0

lextiz
lextiz

Reputation: 318

Probably the event DOMContentLoaded was already fired at the point of time when you set the listener. You can check that document.readyState equals to complete and execute the function without subscribing to the event if it already occurred. In the opposite case if the readyState is loading or interactive you should set the listener as it is currently done in the attached example.

Upvotes: 1

Related Questions