Некорректная работа нескольких Pjax в модальном и не модальном окне.

Общие вопросы по использованию второй версии фреймворка. Если не знаете как что-то сделать и это про Yii 2, вам сюда.
Ответить
i-programmer
Сообщения: 101
Зарегистрирован: 2015.08.24, 18:50

Некорректная работа нескольких Pjax в модальном и не модальном окне.

Сообщение i-programmer »

Если на странице есть несколько `GridView`, обёрнутых в `Pjax` с пагинацией, а также при этом по какому-либо событию подгрузить модальное окно, в котором будет еще несколько подобных гридов - то возникает проблема: идентификаторы, присваемые гриду и pjax'у начинаются опять с нуля (из-за особенностей работы PHP и новых запросов к серверу) и при клике на пагинацию в модальном окне - значения меняются в "обычном", а в модальном ничего не происходит.

Если переприсваивать номера (например если это модалка - к идентификатору прибавить 100), то в модалке при клике на пагинацию второго,третьего и последующих гридах - запрос берется от первого, почему-то, и гриды становятся "копией" первого.

Есть ли какое-то штатное средство фреймворка или рецепт из cookbook, где написано как избежать такого бага-фичи? Я написал жуткий код-костыль, но, боюсь, в будущем мне это аукнется и проекту будет больно. Возможно уже есть решение против такого поведения?
masson
Сообщения: 545
Зарегистрирован: 2012.07.03, 15:59

Re: Некорректная работа нескольких Pjax в модальном и не модальном окне.

Сообщение masson »

1. Какие идентификаторы в модалке генерятся?
2. Какой JS-код в модалке генерится?
i-programmer
Сообщения: 101
Зарегистрирован: 2015.08.24, 18:50

Re: Некорректная работа нескольких Pjax в модальном и не модальном окне.

Сообщение i-programmer »

masson писал(а): 2019.07.02, 16:16 1. Какие идентификаторы в модалке генерятся?
2. Какой JS-код в модалке генерится?
1. Если по умолчанию, то у GridView w0, w1, w2 и т.д. У Pjax p0, p1, p2. Это видно на основе кода из соответствующих виджетов, у которых прописано

Код: Выделить всё

public static $autoIdPrefix = 'w';
у базового виджета в /vendor/yiisoft/yii2/base/Widget.php и

Код: Выделить всё

 public static $autoIdPrefix = 'p';
в /vendor/yiisoft/yii2/widgets/Pjax.php

2. Да такой же, как и на обычной странице. Это же модалка. Запрос и страница и генерирование JS для этих виджетов ничем не отличается. Т.е.

Код: Выделить всё

jQuery('#w0').yiiGridView....
jQuery(document).pjax("#p0 a", .....
jQuery(document).on("submit", "#p0 form[data-pjax]".....
jQuery('#w1').yiiGridView.......
jQuery(document).pjax("#p1 a"......
jQuery(document).on("submit", "#p1 form[data-pjax]".....
Именно в этом вся и загвоздка.
masson
Сообщения: 545
Зарегистрирован: 2012.07.03, 15:59

Re: Некорректная работа нескольких Pjax в модальном и не модальном окне.

Сообщение masson »

1. Если по умолчанию, то у GridView w0, w1, w2 и т.д. У Pjax p0, p1, p2. Это видно на основе кода из соответствующих виджетов, у которых прописано
Я имел в виду фактически, а не по умолчанию. Каким образом номера переписывали (прибавляли 100) ?

Задавать id в коде модалки пробовали?

Код: Выделить всё

Pjax::begin(['id' => 'p' . $someUniqueValue1]);
echo GridView::widget([
    'id' => 'w' . $someUniqueValue1,
    .... 
]);
Pjax::end();

Pjax::begin(['id' => 'p' . $someUniqueValue2]);
echo GridView::widget([
    'id' => 'w' . $someUniqueValue2,
    .... 
]);
Pjax::end();
i-programmer
Сообщения: 101
Зарегистрирован: 2015.08.24, 18:50

Re: Некорректная работа нескольких Pjax в модальном и не модальном окне.

Сообщение i-programmer »

masson писал(а): 2019.07.02, 21:23
1. Если по умолчанию, то у GridView w0, w1, w2 и т.д. У Pjax p0, p1, p2. Это видно на основе кода из соответствующих виджетов, у которых прописано
Я имел в виду фактически, а не по умолчанию. Каким образом номера переписывали (прибавляли 100) ?

Задавать id в коде модалки пробовали?

Код: Выделить всё

Pjax::begin(['id' => 'p' . $someUniqueValue1]);
echo GridView::widget([
    'id' => 'w' . $someUniqueValue1,
    .... 
]);
Pjax::end();

Pjax::begin(['id' => 'p' . $someUniqueValue2]);
echo GridView::widget([
    'id' => 'w' . $someUniqueValue2,
    .... 
]);
Pjax::end();
Да. Пробовал.Анализировал, что запрос ajax, но не pjax (т.е. значит это аякс запрос, но не пагинация, фильтрация или сортировка срабатывающая у pjax) и присваивал номера. Но в итоге, как я писал
при клике на пагинацию второго,третьего и последующих гридах - запрос берется от первого, почему-то, и гриды становятся "копией" первого.
. Причем буквально. Как-будто теряется инфа о текущем состоянии и берется первый. Еще делал проверку, если это и ajax и pjax - то брал айдишник из x-pjax-container и переподставлял. Один фиг. Либо начинается вообще перезагрузка страницы. В общем способов много перепробовал.
Единственное рабочее решение которое я придумал - это генерирование айдишника в зависимости от того что за запрос и сохранение массива ключ-значение (айдишник-текущий объект) - в сессию или кэш и восстановление оттуда. Но не верю, что у yii2 никогда не было такой проблемы ни у кого и нет штатного инструмента.
masson
Сообщения: 545
Зарегистрирован: 2012.07.03, 15:59

Re: Некорректная работа нескольких Pjax в модальном и не модальном окне.

Сообщение masson »

Так вроде работает :

Код: Выделить всё

// Контроллер
    public function actionIndex()
    {
        $dp1 = $dp2 = new ActiveDataProvider([
            'query' => Tag::find(),
            'sort' => ['defaultOrder' => ['id' => SORT_ASC]],
            'pagination' => ['pageSize' => 5],
        ]);

        return $this->render('index', [
            'dp1' => $dp1, 'dp2' => $dp2,
        ]);
    }

    public function actionGetModal()
    {
        $dp1 = $dp2 = new ActiveDataProvider([
            'query' => Tag::find(),
            'sort' => ['defaultOrder' => ['id' => SORT_ASC]],
            'pagination' => ['pageSize' => 5],
        ]);

        // renderAjax !
        return $this->renderAjax('index', [
            'dp1' => $dp1, 'dp2' => $dp2,
        ]);
    }

Код: Выделить всё

// Вьюха
<div class="tag-index">
    <?php
    $route = str_replace('/', '-', Yii::$app->requestedRoute);
    Pjax::$autoIdPrefix = 'pjax-' . $route;
    GridView::$autoIdPrefix = 'grid-' . $route;

    Pjax::begin();
    echo GridView::widget([
        'dataProvider' => $dp1,
        'columns' => ['id', 'title'],
    ]);
    Pjax::end();

    Pjax::begin();
    echo GridView::widget([
        'dataProvider' => $dp2,
        'columns' => ['id', 'title'],
    ]);
    Pjax::end();

    if (!Yii::$app->request->isAjax) {
        echo \yii\helpers\Html::button('Show Modal', [
            'data-toggle' => 'modal', 'data-target' => '#modal_form'
        ]);

        echo Modal::widget(['id' => 'modal_form']);
    }
    ?>
</div>

<?php
if (Yii::$app->request->isAjax) {
    return true;
}

$tagIndexJs = <<< JS
    $('#modal_form').on('show.bs.modal', function (e) {
        $.get('/test/get-modal', [], function(data) {
            $('#modal_form .modal-body').html(data);
        }, 'html');
    });

    $('#modal_form').on('hidden.bs.modal', function (e) {
        $('#modal_form .modal-body').empty();
    });
JS;

$this->registerJs($tagIndexJs);
i-programmer
Сообщения: 101
Зарегистрирован: 2015.08.24, 18:50

Re: Некорректная работа нескольких Pjax в модальном и не модальном окне.

Сообщение i-programmer »

masson писал(а): 2019.07.03, 01:28 Так вроде работает :

Код: Выделить всё

.....
.....
.....
Да. Значит мне надо было чуть более уточняюще написать вопрос. Предположим, что запрос идет на ту же страницу: Такое возможно, когда это например и на той и на другой странице располагается виджет, который, по сути, всегда инициализируется заново и у него нет как такового контроллера. Поэтому айдишники будут чисто p1, p1, p3 и т.д. всегда.
Тем не менее, я на основе вашего примера смог проанализировать всё и найти решение для данной проблемы (конкретно для виджетов). Просматриваю pathInfo запроса и подставляю его как идентификатор. Примерно так:

Код: Выделить всё

$pathInfoParts = explode('/', \Yii::$app->request->pathInfo);
// анализ на вхождение 'index', потому что урл может его и не содержать изначально
// например /tag, а потом запрос идет в /tag/index
if ($pathInfoParts[count($pathInfoParts) - 1] === 'index') 
	array_pop($pathInfoParts);

$id = implode('-', $pathInfoParts) . self::$counter++;

Спасибо вам больше за уделённое время и за наведение на мысли.
Ответить