Skip to content

Consider associating threshold with a target rather than the instance #160

Open
@philipwalton

Description

@philipwalton

As the spec stands today, having the threshold value as a property of the instance make the API quite a bit more complex than it needs to be in any situation that involves observing multiple elements at multiple thresholds via a single IntersectionObserver instance.

Consider an example that wants to observe these three element/threshold combination:

  • #foo at threshold 0.
  • #bar at threshold 0.5
  • #quz at threshold 1

To observe all of these elements using a single IntersectionObserver instance today, you have to instantiate the IntersectionObserver with a threshold of [0, 0.5, 1], and then in the callback you have to loop through each of the targets to make sure it has passed the appropriate threshold (e.g. #qux will trigger the callback when passing a threshold of 0 and 0.5 even though you only care about 1).

A second problem with the current API is, in the above example if I decide I no longer want to monitor #foo for intersections, I can unobserve() the #foo element, but I can't stop observing the 0 threshold, so now #bar and #qux will trigger at a threshold of 0 even though neither element cares about that threshold.

At minimum, we should add a method to update the threshold value, but I think associating the threshold(s) with the targets is a much more intuitive approach.

Here's how I'd want to write the above example:

const io = new IntersectionObserver((records) => {
  // ...
});
io.observe(document.querySelector('#foo'), {threshold: [0]});
io.observe(document.querySelector('#bar'), {threshold: [0.5]});
io.observe(document.querySelector('#qux'), {threshold: [1]});

With these change, the callback is not called for #foo on any threshold other than 0, which means I can avoid writing the logic to check the threshold level in the callback.

It also means I can later call io.unobserve(document.querySelector('#foo')) and not have to worry about the 0 threshold lingering around unnecessarily.

If an element needs to be observed at multiple thresholds but later only one of those threshold values needs to be unobserved, you could do so by specifying the threshold in the second argument to unobserve() exactly as you do in observe().

For example, to observe #foo at threshold 0 and 1 and then later only observe it at 0 you could do the following:

// Observe #foo at 0 and 1.
io.observe(document.querySelector('#foo'), {threshold: [0, 1]});

// Stop observing at 1 but continue to observe at 0.
io.unobserve(document.querySelector('#foo', {threshold: [1]});

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions