3

I tried to lazy load images using Intersection Observable in my angular 7 application. I called Intersection Observable from ngAfterViewInit lifecycle hook. But when i load the application, callback is called twice, once with all the isIntersecting values as true and the next one with the correct isIntersecting values. I am confused with this behaviour.

ngAfterViewInit() {
const imgOne = document.querySelectorAll('[data-class]');

    const options = {
      // root: document
      // threshold: 0
    };

    const observer = new IntersectionObserver((entries, observer) => {
      console.log(entries.length);
      entries.forEach((entry) => {
        // console.log(entry);
        if (!entry.isIntersecting) {
          return;
        } else {
          const el = entry.target;
          if (el.id === ('test' + this.testCount)) {
            console.log(entry);
          }
          // observer.unobserve(entry.target);
        }
      });
    });

    imgOne.forEach((eachQuery) => {
      observer.observe(eachQuery);
    });
 }

https://stackblitz.com/edit/angular-wqbuyr

UPDATE : Now intersection observer is called perfectly, but now a issue occured. Since we are using document.querySelectorAll which returns a static node list, once the array is updted node list is not updated. If i try to use document.getElementsByClassName, an error throws as it is not an Node list ???

Ram
  • 451
  • 10
  • 18
  • Have you tried by this way ```observer.observe(imgOne);```, no need foreach. – Shohel Sep 10 '19 at 16:59
  • Use the class into queryselector not the data attribute ```observer.observe(document.querySelectorAll('img.lzy_img'));``` – Shohel Sep 10 '19 at 17:02
  • It will thrown an error - 'Argument of type 'NodeListOf' is not assignable to parameter of type 'Element'.' as observe gets a single element as its argument not an array of elements. – Ram Sep 10 '19 at 18:48
  • Please create the example to stackblitz – Shohel Sep 11 '19 at 08:45
  • https://stackblitz.com/edit/angular-wqbuyr – Ram Sep 12 '19 at 07:35
  • Now i have made it to work, but now the issue once i increase the count of the array, observer is not taking the new array ??? – Ram Sep 12 '19 at 07:36
  • I solved the issue by removing ngOnInit(), as it was triggering ngAfterViewInit() again after loading. – Ram Sep 14 '19 at 13:36
  • Very interesting, your question... – Shohel Sep 14 '19 at 14:46

2 Answers2

5

Maybe this also works:

if (entry.isIntersecting && Math.floor(entry.intersectionRatio) === 1) { 
  const el = entry.target;
  if (el.id === ('test' + this.testCount)) {
    console.log(entry);
  }
} else {
  return;
}

"If you dont' check intersectionRatio ratio === 1, the observed element will trigger the callback twice, because when immediately passing/leaving 100% threshold, observer will trigger isIntersecting = true, intersectionRatio ~= 0.9 (maybe bug). Chrome somehow gets intersectionRatio slightly above 1 on the first box, so floor the value"

Source: https://codepen.io/mmanney/details/erpZbd

Washington Braga
  • 1,593
  • 15
  • 14
1

I solved the issue by removing ngOnInit(), as it was triggering ngAfterViewInit() again after loading.

Ram
  • 451
  • 10
  • 18