Загружать все больше и больше данных при прокрутке вниз в виджете Kartik Select2

Я работаю над системой управления запасами, с большим количеством продуктов, и клиент хочет отобразить продукты в виджете Select2 точно так же, как виджет kartik, и он хочет представлять данные все больше и больше при прокрутке вниз, доступна ли она или может быть сделано с помощью этого виджета или я должен создать свой собственный? это мой код

<?php
$url = Url::to ( [ 'products-list' ] );
echo Select2::widget ( [
    'name' => 'state_10' ,
    'options' => [
        'id' => 'select_product' ,
        'placeholder' => 'Select Product...' ,
        'multiple' => false ,
        'class' => ''
    ] ,
    'pluginOptions' => [
        'allowClear' => true ,
        'minimumInputLength' => 1 ,
        'ajax' => [
            'url' => $url ,
            'dataType' => 'json' ,
            'data' => new JsExpression ( 'function(params) { return {q:params.term}; }' )
        ] ,
        'escapeMarkup' => new JsExpression ( 'function (markup) { return markup; }' ) ,
        'templateResult' => new JsExpression ( 'function(product) { console.log(product);return product.text; }' ) ,
        'templateSelection' => new JsExpression ( 'function (subject) { return subject.text; }' ) ,
    ] ,
] );
?>

и у меня есть это действие в моем контроллере, и все работает хорошо, но мне нужно начать с отображения ряда продуктов в select2, а затем при прокрутке начать получать все больше и больше

действие контроллера:

    public function actionProductsList($q = null, $id = null) {
        Yii::$app->response->format = Response::FORMAT_JSON;
        $out = ['results' => ['id' => '', 'text' => '', 'qtyLeft' => '', 'serialNumbers' => '']];
        if (!is_null($q)) {
            $query = new Query;
            $query->select(['product_id as id', new Expression("CONCAT(product_name,' -- ',product_qty_left) AS text, product_qty_left as qtyLeft, s.serial_number as serialNumbers")])
                    ->from('product')
                    ->join('LEFT JOIN', 'serial_number s', 's.r_product_id = product.product_id')
                    ->where(['like', 'product_name', $q]);
//                    ->limit(20);
            $command = $query->createCommand();
            $data = $command->queryAll();
            $out['results'] = array_values($data);
        } elseif ($id > 0) {
            $out['results'] = ['id' => $id, 'text' => AppProduct::find()->where(['product_id' => $id])->one()->product_name];
        }
        return $out;
    }

2 ответа

Решение

В соответствии с документацией по использованию нумерации страниц, вы должны указать Select2 добавить все необходимые параметры нумерации страниц в запрос, переопределив ajax.data установка. Текущая страница для извлечения сохраняется в params.page имущество.

Так что вам нужно изменить Select2 к следующему

$url = Url::to ( [ 'products-list' ] );
echo Select2::widget ( [
    'name' => 'state_10' ,
    'options' => [
        'id' => 'select_product' ,
        'placeholder' => 'Select Product...' ,
        'multiple' => false ,
        'class' => ''
    ] ,
    'pluginOptions' => [
        'allowClear' => true ,
        'minimumInputLength' => 1 ,
        'ajax' => [
            'url' => $url ,
            'dataType' => 'json' ,
            'data' => new JsExpression ( 'function(params) { return {q:params.term, page:params.page || 1}; }' )
        ] ,
        'escapeMarkup' => new JsExpression ( 'function (markup) { return markup; }' ) ,
        'templateResult' => new JsExpression ( 'function(product) { console.log(product);return product.text; }' ) ,
        'templateSelection' => new JsExpression ( 'function (subject) { return subject.text; }' ) ,
    ] ,
] );

Select2 будет ожидать pagination.more значение в ответе. Значение more должно быть true или же false, который сообщает Select2, есть ли еще страницы результатов, доступные для поиска:

{
  "results": [
    {
      "id": 1,
      "text": "Option 1"
    },
    {
      "id": 2,
      "text": "Option 2"
    }
  ],
  "pagination": {
    "more": true
  }
}

поэтому измените ваш серверный код, чтобы включить $page параметр и включают в себя limit а также offset в вашем запросе. я использую 5 записей в качестве ограничения в настоящее время вы можете изменить его.

public function actionProductsList($page, $q = null , $id = null ) {
        $limit=5;
        $offset=($page-1)*5;

        Yii::$app->response->format = Response::FORMAT_JSON;
        $out = [ 'results' => [ 'id' => '' , 'text' => '' , 'qtyLeft' => '' , 'serialNumbers' => '' ] ];
        if ( !is_null ( $q ) ) {
            $query = new \yii\db\Query;
            $query->select ( [ 'product_id as id' , new Expression ( "CONCAT(product_name,' -- ',product_qty_left) AS text, product_qty_left as qtyLeft, s.serial_number as serialNumbers" ) ] )
                    ->from ( 'product' )
                    ->join ( 'LEFT JOIN' , 'serial_number s' , 's.r_product_id = product.product_id' )
                    ->where ( [ 'like' , 'product_name' , $q ] )
                    ->offset ( $offset )
                    ->limit ( $limit );
            $command = $query->createCommand ();
            $data = $command->queryAll ();
            $out['results'] = array_values ( $data );
            $out['pagination'] = [ 'more' => !empty($data)?true:false ];
        } elseif ( $id > 0 ) {
            $out['results'] = [ 'id' => $id , 'text' => AppProduct::find ()->where ( [ 'product_id' => $id ] )->one ()->product_name ];
        }
        return $out;
    }

Update

Было несколько исправлений, которые я нашел в приведенном выше коде и изменил

  • Исправить смещение $offset=($page-1)*5; вместо того, чтобы использовать $page лайк ->offset($page) использовать $offset а не как ->offset($offset),
  • Сконфигурируйте больше результатов правильно, чтобы они возвращали значение false, если результатов больше нет, в противном случае он продолжает отправлять вызовы ajax на сервер, даже если результатов больше нет, поэтому измените его на $out['pagination'] = [ 'more' => !empty($data)?true:false ];

kartik\widgets\Select2 имеет поле "данные", в котором вы можете передать массив товаров из баз данных и отфильтровать список товаров в соответствии. В вашем случае я могу использовать приведенный ниже код для реализации такого сценария, как

echo Select2::widget([
    'name' => 'state_10',
    'options' => [
        'placeholder' => 'Select Product...',
        'multiple' => false,
    ],
    'data' => ArrayHelper::map(Product::find()->all(), 'id', function($model){
            return "{$model->product_id},{$model->product_name}--{$model->product_qty_left}, {$model->product_qty_left}, {$model->relation2serial->serial_number} ";
        });

У меня есть представление, что у вас есть модель продукта по отношению к модели serial_number на случай, если вам понадобятся отношения к этой модели и другим моделям для вашего случая.

Надеюсь помогает!!

Другие вопросы по тегам