21

I'm watching a video on Intersection Observer and I've copied his script word for word and I'm somehow getting this error. Someone had the same error but solved their problem by changing querySelectorAll to querySelector. Even when I copied their code and changed it to querySelector it still didn't work on my end. The code below is mine. I'm using vs code live server.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <link rel='stylesheet' href='style.css'>
    <script src='script.js'></script>
</head>
<body>
    <section class = 'section1'></section>
    <section></section>
    <section></section>
    <section></section>
    <section></section>
    <section></section>
</body>
</html>
const sectionOne = document.querySelector('.section1');

const options = {};

const observer = new IntersectionObserver(function
(entries, observer){
    entries.forEach(entry => {
        console.log(entry);
    });
}, options);

observer.observe(sectionOne);
body{
    padding: 0;
    margin: 0;
}

section{
    height: 100vh;
    width:100%;
}
section:nth-child(odd){
    background: lightcoral
}
Joheb
  • 423
  • 1
  • 3
  • 7
  • `querySelector` returns `Element | null`, so you'll need to assert the element exists somehow. For example try `observer.observe(sectionOne!)` or `observer.observe(assertExists(sectionOne))`. – cs95 Aug 15 '20 at 17:39
  • Didnt notice the element comes up null. Im using defer in my script tag to load the page before the script so the element can exist – Joheb Aug 15 '20 at 20:28

7 Answers7

9

The element returns as null because the script runs before the HTML is parsed. I used defer in my script tag to avoid this problem.

<script src='script.js' defer></script>
Joheb
  • 423
  • 1
  • 3
  • 7
  • using assertExists would catch this problem immediately. Good work debugging. – cs95 Aug 15 '20 at 22:46
  • isn't there a natural way to do this...like run the script when the entire window is ready? or is that not related? – klewis Sep 08 '21 at 17:15
4

You need to make sure the IntersectionObserver script will run after the DOM is completely loaded.

document.addEventListener("DOMContentLoaded", function(){
    
      // your instersectionobserver code here
    
    
    });
2

your selection is for the first element as querySelector take the first one if you want to select all then use querySelectorAll, and loop through them so the observer can observe them one by one, it should be as follow:

const sections = document.querySelectorAll('section');

const options = {};

const observer = new IntersectionObserver(function
(entries, observer){
entries.forEach(entry => {
    console.log(entry);
});
}, options);

// loop 
sections.forEach( section => {
observer.observe(section);
});
B001ᛦ
  • 2,036
  • 6
  • 23
  • 31
0

Actually it looks like the example you posted works fine, you can check it in this JSFiddle I made: https://jsfiddle.net/sandro_paganotti/pomtng6f/3/

const sectionOne = document.querySelector('.section1');
const options = {};

const observer = new IntersectionObserver(function
 (entries, observer){
    entries.forEach(entry => {
       console.log(entry);
 });
}, options);

observer.observe(sectionOne);

Of course being the observer only attached to the first section it'll only fire when the first section enters or leaves the viewport.

Sandro Paganotti
  • 2,295
  • 16
  • 12
0

Add

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

document = your div.

You have to be sure that the DOM has loaded, and when it is "ready" then it starts :).

Elisei Nicolae
  • 293
  • 2
  • 12
0

I believe intersectionObserver.observe can only observe one element. I've noticed that when there are multiple div elements with same class names, observe returns uncaught typeError.

Others who got it working by changing from querySelectorAll to querySelector might be because they had a several div with same class names.

minervatea
  • 27
  • 5
0
function playPauseVideo() {
let videos = document.querySelectorAll("video");
videos.forEach((video) => {
    // We can only control playback without insteraction if video is mute
    video.muted = true;
    // Play is a promise so we need to check we have it
    let playPromise = video.play();
    if (playPromise !== undefined) {
        playPromise.then((_) => {
            let observer = new IntersectionObserver(
                (entries) => {
                    entries.forEach((entry) => {
                        if (
                            entry.intersectionRatio !== 1 &&
                            !video.paused
                        ) {
                            video.pause();
                        } else if (video.paused) {
                            video.play();
                        }
                    });
                }, {
                    threshold: 0.2
                }
            );
            observer.observe(video);
        });
    }
});

}

// And you would kick this off where appropriate with: playPauseVideo();