Select2 v4 как рисовать результаты с помощью AJAX

Я пытаюсь разбивать страницы (каждые 25 строк) с помощью Select2 4.0, но я не знаю, как это сделать. Кто-нибудь знает, как это сделать?

Если пользователь достигает конца 25 строк, и если есть больше строк, я бы хотел загрузить его и показать его.

Вот мой HTML-шаблон

<div class="form-group">
    {!! Form::select('breed_id', $breeds, null, ['class' => 'form-control', 'id' =>'breed_id'] ) !!}
</div>

И вот JavaScript для Select2.

$("#breed_id").select2({
    placeholder: 'Breed...',
    width: '350px',
    allowClear: true,
    ajax: {
        url: '',
        dataType: 'json',
        data: function(params) {
            return {
                term: params.term
            }
        },
        processResults: function (data, page) {
            return {
                results: data
            };
        },
        cache: true
    }
});

И это код для моего контроллера

if ($request->ajax())
{
    $breeds = Breed::where('name', 'LIKE',  '%' . Input::get("term"). '%')->orderBy('name')->take(25)->get(['id',DB::raw('name as text')]);

    return response()->json($breeds);
}

Также, когда я пытался поставить params.page, он говорит "undefined".

Ответ 1

Select2 поддерживает разбиение на страницы при использовании удаленных данных с помощью клавиши pagination, которая выходит из processResults.

Для бесконечной прокрутки ожидается, что объект pagination имеет свойство more, которое является логическим (true или false). Это сообщит Select2, должен ли он загружать больше результатов при достижении дна или если он достиг результатов.

{
  results: [array, of, results],
  pagination: {
    more: true
  }
}

В вашем случае у вас есть возможность формировать ваши результаты. Таким образом, вы можете изменить свой ответ JSON в соответствии с ожидаемым форматом, что означает, что вам даже не понадобится использовать processResults.

Select2 может передать номер страницы как page, если вы измените функцию ajax.data, чтобы вернуть ее.

data: function(params) {
    return {
        term: params.term || "",
        page: params.page || 1
    }
},

И тогда вы сможете получить страницу с помощью Input::get('page'). И вы можете рассчитать общее количество результатов, чтобы пропустить с помощью (page - 1) * resultCount, где resultCount - 25 в вашем случае. Это позволит вам изменить запрос, чтобы объединить LIMIT и OFFSET, чтобы получить нужные результаты.

$page = Input::get('page');
$resultCount = 25;

$offset = ($page - 1) * $resultCount;

И вы можете использовать следующий запрос для генерации запроса LIMIT/OFFSET (на основе этого вопроса о переполнении стека.

$breeds = Breed::where('name', 'LIKE',  '%' . Input::get("term"). '%')->orderBy('name')->skip($offset)->take($resultCount)->get(['id',DB::raw('name as text')]);

Итак, теперь $breeds будет содержать только запрошенные результаты. Единственное, что осталось сделать - это сформировать ответ, чтобы соответствовать тому, как Select2 ожидает его. Вы можете определить, есть ли больше страниц, проверив общее количество результатов и посмотрев, превысили ли вы лимит.

$count = Breed::count();
$endCount = $offset + $resultCount;
$morePages = $endCount > $count;

Итак, теперь $morePages должно быть логическим, что именно то, что Select2 ищет в pagination.more. Теперь вам просто нужно сформировать ответ в соответствии с форматом, который я упоминал ранее.

$results = array(
  "results" => $breeds,
  "pagination" => array(
    "more" => $morePages
  )
);

И затем рендеринг, который

return response()->json($results);

Собирая все вместе, вы получите это для JavaScript

$("#breed_id").select2({
    placeholder: 'Breed...',
    width: '350px',
    allowClear: true,
    ajax: {
        url: '',
        dataType: 'json',
        data: function(params) {
            return {
                term: params.term || '',
                page: params.page || 1
            }
        },
        cache: true
    }
});

И для вашего контроллера

if ($request->ajax())
{
    $page = Input::get('page');
    $resultCount = 25;

    $offset = ($page - 1) * $resultCount;

    $breeds = Breed::where('name', 'LIKE',  '%' . Input::get("term"). '%')->orderBy('name')->skip($offset)->take($resultCount)->get(['id',DB::raw('name as text')]);

    $count = Breed::count();
    $endCount = $offset + $resultCount;
    $morePages = $endCount > $count;

    $results = array(
      "results" => $breeds,
      "pagination" => array(
        "more" => $morePages
      )
    );

    return response()->json($results);
}