Scope issue in Intersection observer API

var allSec = document.querySelectorAll(".commonclass");
let counter = 0;
allSec.forEach((article) => {
  if (article) {
	  const observer = new IntersectionObserver((entries) => {
	      observerCallback(entries)
	  });
	  observer.observe(article);
	  console.log(article);
  }
})

const observerCallback = (entries) => {
  entries.forEach((entry) => {
	   if (entry.isIntersecting) {
	   	counter = counter + 1;
	   	// console.log(counter);
	   }
  });
};
console.log(counter);

There are 11 article tags inside a section with class = slider. In full width only 3 are visible.
So the counter should give 3, but the value is not accessible outside the loop? Is this a local Vs global variable scope issue?

Hi @codeispoetry, why the console correctly logs

0 
1
2
3

where the zero comes from the log outside the callback (which only fires later asynchronously). If you need to check for the intersecting articles initially, you might do so by comparing their positions (as returned by getBoundingClientRect()) with the window.scrollX / window.scrollY and
window.innerWidth / window.innerHeight respectively.

1 Like

Hi there, The coinsole correctly logs because the console.log is currently inside the callback function.

But when I try to see the console.log at the end of the entire script.

Now check aftre clearing the console →

Eventually I need this updated variable counter so that I can use it in my another programming logic.

Yes I did un-comment all the logging lines of your your pen, sorry I should have mentioned that. Anyway as I said, the variable is getting updated but only after you’re logging it to the console in the last line of your script. The sequence of events is as follows:

  1. You initialise the intersection observer
  2. You’re logging counter to the console
  3. The intersection observer calls back, incrementing counter

Try wrapping the last console.log() in a random setTimeout() to see that it actually does work.

1 Like

You are right, I tried this and it worked:

function consoleTimer(){
  console.log(counter);
}
setTimeout(consoleTimer, 2000);

This blog was quiet helping →

1 Like

I had something working here. with this version of the JS →

var allSectionArticleNumber = 0;
const nextClick = document.querySelector(".next");
nextClick.addEventListener('click', event => {
	console.log("Next event clicked");
	event.preventDefault();
	var nodeHolidayClass = document.querySelectorAll("article.holidayclass");
	var nodeCommonClass = document.querySelectorAll("article.commonclass:not(.holidayclass,.holidayclass2)");

	if (nodeCommonClass.length >= allSectionArticleNumber) {		
		for (let i = 0 ; i < allSectionArticleNumber; i++) { 
			nodeCommonClass[i].classList.add("holidayclass2");
		}
		for (let i = 0 ; i < allSectionArticleNumber; i++) { 
			nodeHolidayClass[i].classList.remove("holidayclass");
		}		
	}

});

const previousClick = document.querySelector(".previous");
previousClick.addEventListener('click', event => {
	console.log("Previous event clicked");
	event.preventDefault();
	var nodeHolidayClass2 = document.querySelectorAll("article.holidayclass2");
	var nodeCommonClass = document.querySelectorAll("article.commonclass:not(.holidayclass,.holidayclass2)");	
	for (let i = 1 ; i <= allSectionArticleNumber; i++) { 
		nodeHolidayClass2[nodeHolidayClass2.length-[i]].classList.remove("holidayclass2");
	}
	for (let i = 0 ; i < nodeCommonClass.length; i++) {
		nodeCommonClass[i].classList.add("holidayclass");
	}	
});

In this allSectionArticleNumber is hardcoded with a numerical value assigned = 3.

but I wanted to achieve that this number should come dynamically based on the number of article element visible in the viewport. I adjusted by using InteresectionObserver API.

I put this additional code →

var allSectionArticleNumber = 0;
window.addEventListener('load', function () {
	var allSectionArticle = document.querySelectorAll(".commonclass");
	allSectionArticle.forEach((article) => {
	  if (article) {
		  const observer = new IntersectionObserver((entries) => {
		      observerCallback(entries)
		  });
		  observer.observe(article);
		  console.log(article);
	  }
	})

	const observerCallback = (entries) => {
	  entries.forEach((entry) => {
		   if (entry.isIntersecting) {
		   	allSectionArticleNumber = allSectionArticleNumber + 1;
		   }
	  });
	};
}, false);

function consoleTimer(){
  console.log(allSectionArticleNumber);
}
setTimeout(consoleTimer, 1000);

I also enveloped the code inside the window load add event listener so that viewport article numbers are calculated once on every page load.

but after the first next click, the sliding stops. where am I going wrong? console doesn’t generate any error.

This topic was automatically closed 91 days after the last reply. New replies are no longer allowed.