Intersection Observer API

Hello,
I have made a discovery and I thought I share it here to eventually get feedbacks.
In our application we manage a very long list of customer orders and each customer orders have a long list of lines.
When a user load the page, it used to trigger 1 subscribe and 1 method call for each sub templates and if we have 1000 orders, it is a lot of load on our server.

I have implemented the Intersection Observer API (Intersection Observer API - Web APIs | MDN) and it seems very promising for my use case.

It looks like this :

template.html

<template name="customerOrders">
    {{#each customerOrderId in customerOrderIds}}
        {{>customerOrder customerOrderId=customerOrderId}}
    {{/each}}
</template>

<template name="customerOrder">
    <div id="customerOrderDiv-{{customerOrderId}}">
        {{customerOrder.num}}
        {{#each line in lines}}
            {{>customerOrderLine line=line}}
        {{/each}}
    </div>
</template>

template.js

Template.customerOrder.onCreated(function() {
    this.lines = new ReactiveVar(false);
});
  
Template.customerOrder.onRendered(function() {
    const instance = this;
    const element = document.querySelector('#customerOrderDiv-' + this.data.coId);
    const observer = new IntersectionObserver(function(entries, observer) {
        entries.forEach(entry => {
        if (entry.isIntersecting) {
            observer.unobserve(element);
            instance.subscribe('customer-order', instance.data.customerOrderId);
            Meteor.call('customer-order/lines', instance.data.customerOrderId, function(err, res) {
                if (err) {
                    console.error(err);
                    return;
                }
                instance.lines.set(res);
            });
        }
        });
    }, {root: null, rootMargin: '0px', threshold: 0.05});
    observer.observe(element);
});

Template.customerOrder.helpers({
    customerOrder: function() {
        return CustomerOrders.findOne(this.customerOrderId);
    },
    lines: function() {
        return Template.instance().lines.get();
    },
});

How it work ?
When the page is displayed, only the firsts visible elements trigger the subscribe and call. As soon as the calls are triggered we can unobserve the observer (to avoid double calls)
When the user scroll down the page, we progressively subscribe and call methods.

I like the approach and will test in production.
Do you see improvements or drawbacks ?
Thanks

3 Likes

@dokithonon I don’t have an opinion, but I’d like to know how this has worked out so far. Can you share an update?

If this has worked well for you, can I ask you to think about doing a presentation on this for a meetup presentation, and perhaps, for Impact 2022? If needed, I can help you work on it.

Hello,
Yes this works well. Intersection observers are a very nice feature to do infinite scroll with lazy loading.
Easy to implement.

Thanks for your proposal for presenting but we are a bit overloaded at the moment…

Thanks for the update. Impact 2022 is scheduled for this Fall, so not an immediate request. However, if this is still not possible for you, we’ll explore reproducing your work and find someone else to present. I think it’s a worthwhile model to explore for Meteor developers and how other frameworks such as Gatsby uses it.

So seeing results of an implementation, with comparative metrics (baseline, with IO API implementation) could be quite informative. If you change your mind, let me know. And thanks again for sharing.