6

I'm using the Intersection Observer API on a site. For every instance of using it, I'm using the same config (main viewport). My issue is that I need to have different things happen when the callback is fired. For some, I want to lazy load an image. For some, I want to initialize a carousel, etc.

Is there a way to use the same observer for all of these different applications or do I have to use a different observer for each unique callback?

pretzelhammer
  • 13,874
  • 15
  • 47
  • 98
Mike
  • 73
  • 1
  • 3

1 Answers1

5

You can reuse the same intersection observer and same callback for all your different targets, since the callback is provided the target element you can use that information to customize what the callback does.

In example below I change the message on the screen depending on which differently colored div is in view reusing the same IntersectionObserver instance and same callback function:

const message = document.getElementById('message');

function callbackRouter(entries, observer) {
  let entry = entries[0];
  let target = entry.target;
  if (entry.intersectionRatio > 0) {
    message.textContent = target.classList + " is in view!";
    if (target.dataset.callback) {
      window[target.dataset.callback](target);
    }
  }
}

function lazyLoadImage(target) {
    console.log('lazy load an image here');
}

function initCarousel(target) {
  console.log('initialize a carousel here');
}

function sendAsyncRequest(target) {
  console.log('send an async request here');
}

function doWhatever(target) {
  console.log('literally do whatever you want');
}

const observer = new IntersectionObserver(callbackRouter);
const boxes = document.querySelectorAll('.box');
boxes.forEach(observer.observe.bind(observer));
.box {
  height: 1000px;
}

.violet {
  background-color: violet;
}

.green {
  background-color: green;
}

.tomato {
  background-color: tomato;
}

.orange {
  background-color: orange;
}

#message {
  position: fixed;
  top: 20px;
  left: 20px;
  background-color: white;
  height: auto;
  padding: 10px 20px;
}
<div class="tomato box" data-callback="lazyLoadImage"></div>
<div class="violet box" data-callback="initCarousel"></div>
<div class="orange box" data-callback="sendAsyncRequest"></div>
<div class="green box" data-callback="doWhatever"></div>
<div id="message"></div>
pretzelhammer
  • 13,874
  • 15
  • 47
  • 98
  • Thanks but this is still using the same callback to do the same thing to every entry. My use case is having different callbacks based on the target. For example, one entry's target is an image that loads on intersection. Another entry's target is a carousel that needs to be started on intersection. Is there a way to use the same observer for all targets or do I need to make a different observer for each different callback use case. – Mike Sep 24 '18 at 01:08
  • @Mike A callback is just like any other function, there's nothing special about it. You can call other functions from a function. You can also forward the arguments from one function to another. Use the callback to call other functions if you want different behaviors depending on the intersection target. You can even put the callbacks directly on the node targets within the DOM itself. I've updated my snippet above. – pretzelhammer Sep 24 '18 at 01:35
  • Thanks! This works to call it with a data-* attribute. My other idea was to fire a custom event on intersect. I guess the real question was how to tie a function to a DOM element. – Mike Sep 24 '18 at 11:34