Render results with the infiniteHits connector

Hello everyone,

I am trying to implement infiniteScroll for Magento2, so I followed the steps provided in this tutorial and everything worked as expected. However I’m stuck trying to render the hits using a custom template. The template works fine when using the default instantsearch infiniteHits widget (the one created without using a connector), so my guess is there’s something missing from my render function.

code for creating the widget:

// 1. Create a render function
let lastRenderArgs;
const renderInfiniteHits = (renderOptions, isFirstRender) => {
    const { hits, showMore, widgetParams } = renderOptions;
    const { container, templates, cssClasses, transformItems, showPrevious, escapeHits } = widgetParams;

lastRenderArgs = renderOptions;

if (isFirstRender) {
    // Do some initial rendering and bind events
    const sentinel = document.createElement('div');
    $(container).append("<div><div class='ais-InfiniteHits'><ol class='ais-InfiniteHits-list'></ol></div></div>");
    $(container)[0].appendChild(sentinel);

    const observer = new IntersectionObserver(entries => {
        entries.forEach(entry => {
            if (entry.isIntersecting && !lastRenderArgs.isLastPage) {
                showMore();
            }
        });
    }, {passive: true});

    observer.observe(sentinel);

    return;
}

// TODO render the widget
// Render the widget
$(container)[0].querySelector('ol').innerHTML = `
    ${hits
    .map(
        item => templates.item
    )
    .join('')}
    `;
};

// 2. Create the custom widget
const customInfiniteHits = 
algoliaBundle.instantsearch.connectors.connectInfiniteHits(
    renderInfiniteHits
);

// instance params
const customInfiniteHitsParams = {
    // instance params
    container: '#instant-search-results-container',
    templates: {
        empty: '',
        item: $('#instant-hit-template').html(),
        showMoreText: algoliaConfig.translations.showMore
    },
    cssClasses: {
        loadPrevious: ['action', 'primary'],
        loadMore: ['action', 'primary']
    },
    transformItems(items) {
        return items.map(function (item) {
            item.__indexName = search.helper.lastResults.index;
            item = transformHit(item, algoliaConfig.priceKey, search.helper);
            // FIXME: transformHit is a global
            item.isAddToCartEnabled = algoliaConfig.instant.isAddToCartEnabled;
            algoliaBundle.instantsearch.showPrice(item);
            return item;
        });
    },
    showPrevious: false,
    escapeHits: true
}

// 3. Instantiate
search.addWidgets([
    customInfiniteHits(customInfiniteHitsParams)
]);

any help would be much appreciated :slight_smile: also this is my first time posting so sorry in advance if this question is missing anything

Hi @mohamed2, could you provide a code sandbox to help us troubleshoot? You can find a starter template here.

1 Like

Hey, turns out templates aren’t available when using a connector, so I had to manually compile the templates. Would’ve been nice if it was mentioned in the docs or as a comment somewhere in the code. Here are the changes I had to make:

// 1. Create a render function
let lastRenderArgs;
const renderInfiniteHits = (renderOptions, isFirstRender) => {
    const { hits, showMore, widgetParams } = renderOptions;
    const { container, templates, cssClasses, transformItems, showPrevious, escapeHits } = widgetParams;

    lastRenderArgs = renderOptions;

    if (isFirstRender) {
        // Do some initial rendering and bind events
        const sentinel = document.createElement('div');
    
        ...
    }

    // TODO render the widget
    // Render the widget

    // Templates are not available when using a connector, so manually compile the template
    var hitTemplate = algoliaBundle.Hogan.compile(templates.item);
    // Render hit items
    $(container)[0].querySelector('ol').innerHTML = `
        ${hits
            .map(
                item => '<li class="ais-InfiniteHits-item">' + hitTemplate.render(item) + '</li>'
            )
            .join('')}
           `;
};