AJAX-пагинация (кнопка загрузить ещё) в October CMS

Написал я компонент, и оказалось так, что вывожу сотню-другую элементов в рамках этого компонента. Естественно, что для этого добра нужна пагинация.

Не захотел делать пагинацию в виде циферок, по клику на которые меняются страницы с элементами. Решил, что сделаю кнопку «Загрузить ещё» при помощи AJAX.

Не буду подробно описывать про компонент и т.д., опишу самые главные вещи, чтобы копировал-вставил и заработало.

В первую очередь засунем всю списочную часть из default.htm в отдельный partial и добавим div#list и div#load-more-button:

default.htm

<div id="list">
    {% partial '@_list' %}
</div>

<div id="load-more-button" class="loadmore">
    <a data-request="onLoadMore" data-request-data="page: 1" href="#">Загрузить ещё</a>
</div>

div#list нужен для вывода списка, а div#load-more-button для замены кнопки на ничего, в случае, если кончились элементы.

Добавляем в модель функцию scopeListFrontEnd, которая запрашивает содержимое из бд, попутно разбивая его на страницы:

MyModel.php

class MyModel extends Model 
{
    public function scopeListFrontEnd($query, $options = []) 
    {
        extract(array_merge([
            'page'    => 1,
            'perPage' => 10,
        ], $options));

        return $query->paginate($perPage, $page);
    }
}

Как параметры, мы передаём текущую страницу и количество элементов на странице.

Теперь расширим класс компонента:

ComponentClass.php

class ComponentClass extends ComponentBase
{
    public $items;

    public function defineProperties()
    {
        'pageNumber' => [
            'title'       => 'Page Number',
            'description' => 'Description',
            'type'        => 'string',
            'default'     => '{{ :page }}',
        ],
    }

    public function onRun()
    {
        $this->items = $this->loadItems():

        // если в url страница больше, чем всего страниц, то редиректим на последнюю
        if ($pageNumberParam = $this->paramName('pageNumber')) {
            $currentPage = $this->property('pageNumber');
            if ($currentPage > ($lastPage = $this->items->lastPage()) && $currentPage > 1) {
                return Redirect::to($this->currentPageUrl([$pageNumberParam => $lastPage]));
            }
        }
    }

    public function loadItems()
    {
        $items = MyModel::listFrontEnd([
            'page'    => $this->property('pageNumber'),
            'perPage' => 10,
        ]);

        return $items;
    }

    /*
     * Данная функция вызывается по клику на кнопку "Загрузить ещё"
     */
    public function onLoadMore()
    {
        // получаем номер страницы
        $pageNumber = Input::get('page') + 1;

        // выставляем номер страницы и готовим данные
        $this->setProperty('pageNumber', $pageNumber);
        $this->onRun();

        if ($pageNumber < $this->items->lastPage()) {
            $more_link = $this->renderPartial('@_morelink.htm', ['pageNumber' => $pageNumber]);
        } else {
            $more_link = ''; // если мы достигли последней страницы, кнопка больше не нужна
        }

        return [
            // если перед селектором стоит @, новое содержимое будет добавляться
            // в конец, а не заменять старое
            '@#list'            => $this->renderPartial('@_list.htm'),
            '#load-more-button' => $more_link,
        ];
    }

}

Не забудь для страницы добавить в url "/page/:page?/", и готово 🙂

Комментарии (9):

  1. Vlad Ответить

    Здравствуйте!
    Пытаюсь воспользоваться решением «копировал-вставил и заработало» и никак:

    Call to a member function lastPage() on null

    В этой строке:

    if ($currentPage > ($lastPage = $this->items->lastPage()) && $currentPage > 1) {

    Почему так?

    P.S. В этой строке исправлено questions на items

    12.08.2019 в 03:26
    • ref Ответить

      Привет! Чтобы разобраться, нужно видеть код модели и компонента. Закинь код на https://gist.github.com и скинь сюда, либо на почту — ref@deadblog.ru

      12.08.2019 в 10:47
      • G'olib

        public function onRun()
        {
        $items = $this->loadItems():

        // если в url страница больше, чем всего страниц, то редиректим на последнюю
        if ($pageNumberParam = $this->paramName('pageNumber')) {
        $currentPage = $this->property('pageNumber');
        if ($currentPage > ($lastPage = $this->items->lastPage()) && $currentPage > 1) {
        return Redirect::to($this->currentPageUrl([$pageNumberParam => $lastPage]));
        }
        }
        }

        здесь просто глобального $items надо инициализировать

        15.01.2020 в 17:52
  2. G'olib Ответить

    $this->items = $this->loadItems(); вот так

    15.01.2020 в 17:53
    • ref Ответить

      Спасибо, поправил в статье!

      15.01.2020 в 18:15
  3. G'olib Ответить

    $this->renderPartial(‘@_morelink.htm’, [‘pageNumber’ => $pageNumber]);
    здесь на партиали что я должен делать?

    16.01.2020 в 14:10
  4. G'olib Ответить

    я уже разобрался спасибо за статья!

    16.01.2020 в 15:45
  5. Triad Ответить

    Вопрос новичка. MyModel.php, ComponentClass.php где эти файлы находятся или мы создаем новый плагин с данными файлами? Как должна выглядеть иерархия файлов.

    01.08.2020 в 03:15
    • ref Ответить

      Пример в статье — как сделать пагинацию в своём плагине.
      ComponentClass.php — это класс компонента, он находится в /plugins/author/pluginName/components/
      MyModel.php — это класс модели, он находится в /plugins/author/pluginName/models/

      01.08.2020 в 15:45

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *