Skip to content

Instantly share code, notes, and snippets.

@luca-rath
Last active October 15, 2023 06:52
Show Gist options
  • Save luca-rath/d16c0ad74fa06da49fed22404a53398b to your computer and use it in GitHub Desktop.
Save luca-rath/d16c0ad74fa06da49fed22404a53398b to your computer and use it in GitHub Desktop.
Sulu smart_content load-more link

The javascript component, which handles the loadMore could look like this:

// components/AjaxLink.js

import * as $ from 'jquery';

export default class AjaxLink {
    $el;
    $container;
    loading = false;
    enableLoader;
    loadingClass;

    initialize = (el, options) => {
        this.$el = $(el);
        this.$container = options.container || $(`#${el.id}-container`);
        this.enableLoader = !!options.loadingClass || !!options.enableLoading;
        this.loadingClass = options.loadingClass || `${this.getFirstClass(this.$el)}--loading`;

        this.bindEvents();
    };

    getFirstClass = ($item) => {
        return $item[0].classList[0];
    };

    bindEvents = () => {
        this.$el.on('click', this.handleClick);
    };

    get url() {
        const url = new URL(this.$el.attr('href'), window.location.href);
        url.searchParams.set('partial', 'true');

        return url.href;
    }

    appendItems = (items) => {
        this.$container.append(items);
    };

    changeHref = (href) => {
        this.$el.attr('href', href);
    };

    removeLoadMoreLink = () => {
        this.$el.remove();
    };

    toggleLoadingClass = () => {
        this.$el.toggleClass(this.loadingClass);
    };

    handleClick = (e) => {
        e.preventDefault();

        if (this.loading) {
            return;
        }

        this.loading = true;

        if (this.enableLoader) {
            this.toggleLoadingClass();
        }

        $.ajax(this.url, {
            error: () => {
                this.removeLoadMoreLink();
            },
            success: (data) => {
                data = $(data);

                const items = data.find(`#${this.$container.attr('id')}`).html();
                const loadMoreLink = data.find(`#${this.$el.attr('id')}`);

                this.appendItems(items);

                if (loadMoreLink.length) {
                    this.changeHref(loadMoreLink.attr('href'));
                } else {
                    this.removeLoadMoreLink();
                }
            },
            complete: () => {
                if (this.enableLoader) {
                    this.toggleLoadingClass();
                }

                this.loading = false;
            },
        });
    };
}

Register it using:

// main.js

import * as web from '@sulu/web';
import AjaxLink from './components/AjaxLink';

web.registerComponent('ajax-link', AjaxLink);

window.web = web;

In the twig you can implement it as following:

{% if content.items|length %}
    <div class="container">
        {% set ajaxLinkId = register_component('ajax-link', { enableLoading: true }) %}

        <div class="grid" id="{{ ajaxLinkId }}-container">
            {% for item in content.items %}
                ...
            {% endfor %}
        </div>

        {% if view.items.paginated and view.items.hasNextPage|default %}
            <div>
                {% set queryParams = app.request.query.all|merge({
                    'page': view.items.page + 1,
                }) %}

                <a class="load-more" id="{{ ajaxLinkId }}" href="?{{ queryParams|url_encode }}" rel="next">
                    Load more
                </a>
            </div>
        {% endif %}
    </div>
{% endif %}

Your smart content should like this:

<property name="items" type="smart_content">
    <meta>
        <title lang="en">Items</title>
    </meta>

    <params>
        <param name="provider" value="pages"/>
        <param name="max_per_page" value="12"/>
        <param name="page_parameter" value="page"/>
        <param name="properties" type="collection">
            <param name="title" value="title"/>
        </param>
    </params>
</property>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment