What could cause addEventListener to execute successfully, but not work in DOMContentLoaded?

(Edit: solved for the most part. Something wonky w/ a legacy theme's code)

TLDR: adding event listener to anchor's click works in jQuery's ready and the later-executed Window's load, but not in Document's DOMContentLoaded, despite compiling and running smoothly. Any explanation for why/how this happens?

I have some code like this:

<a id="add-btn" role="button">Add</a>

I wanted to dynamically attach a click event to it in a separate JS script tag.

<script>
    $(document).ready(() => {
        let btn = document.getElementById("add-btn");
        btn.addEventListener("click", ev => {
            console.log("'Add' clicked!");
        });
        console.log("initialized!");
    });
</script>

This runs perfectly as expected. However, I don't want my code to rely on jQuery. So, naturally, I googled the suggested alternative, and swapped to DOMContentLoaded:

document.addEventListener("DOMContentLoaded", () => {
    // Rest of code
});

Now it compiles, runs, and even continues to log "initialized!" as expected, BUT it does not actually attach the event listener to the anchor element. If I change it to Window's load event, it works (my short-term workaround), but I still don't understand why DOMContentLoaded didn't do the job since everything I read online says it should handle it. It's not like the anchor element hasn't loaded yet, and plenty of other "interactive" readystate stuff works, so why doesn't this?

Is there some rule or documentation someone could point me to for an explanation? Thanks.

Posted Feb 27, 2022, 5:41 PM UTC · edited

06
ssddanbrownphp•

This should work fine: https://jsfiddle.net/e65od943/

I'd guess it's related to something else in terms of how the link is created or potentially some other code interfering. If you're getting the "initialized!" then the listener should be added otherwise, if the button was not accessible, you'd get an error in your console. Do you potentially have something else listening to the button click?

If you could share a non-working example that would help others to diagnose the cause.

1
willnationsdevOPfull-stack dotnet php js•

Hmmm, ok. So then it must be something on our side we're not seeing. Alright, thanks. I'll investigate further and report back if I find anything. I appreciate it.

Edit: I tested the scenario on a separate blank page, and it worked fine, so it definitely has something to do with something else being delivered to the webpage rather than anything to do with the code itself. My guess is that some portion of our organization's legacy theme code is hijacking/manipulating event handlers in some absurd way. But because it already relies on jQuery anyway, using jQuery's ready function probably results in seamless logic that isn't impacted by whatever other stuff is going on. That's my theory at least. Long story short, I know now that it wasn't anything wrong with my understanding of web principles, and that was my major concern.

1
RotationSurgeonfront-end•

Is there any chance that you have stylesheets being linked after the script in your markup? Especially ones of any particular size?

1
willnationsdevOPfull-stack dotnet php js•

No, there's no chance of that. Server code is ensuring that all scripts are appended to the end of the document. I also just confirmed on the webpage in question.

1
RotationSurgeonfront-end•

Well, that was my singular shot in the dark, as that can affect the behavior of DOMContentLoaded differently than the window.load event.

Hmm.

Actually...come to think of it, we ran into this exact problem last week! We chalked it up to some interplay with some third-party scripts the client had added on their own via the CMS features of our platform, and resolved it by applying the event listener to the body instead of the affected element, then delegating the event to the correct target element.

2