Почему вынесение переменной за pjax влияет на работу DatePicker?

Есть простой код:

Pjax::begin(['id' => "test-grid-pjax", 'enablePushState' => false, 'enableReplaceState' => false]);

echo GridView::widget([
    'id' => "test-grid",
    'dataProvider' => $dataProvider,
    'filterModel' => $searchModel,
    'columns' => $columns,
]);

Pjax::end();

И есть определение колонок. Они вынесены в переменную:

$columns = [
    'id',
    [
        'attribute' => 'start_guarantee_period',
        'value' => function ($model) {
            return $model->start_guarantee_period;
        },
        'filter' => kartik\date\DatePicker::widget(['value' => $searchModel->start_guarantee_period, 'name' => 'ItemSearch[start_guarantee_period]', 'pluginOptions' => [
                'format' => 'dd.mm.yyyy',
                'todayHighlight' => true
            ],
        ]),
    ],
];

DatePicker используется от картика, то есть этот У DatePicker есть иконки выбора даты и сброса.

  • Если инициализацию переменной $columns поместить внутрь Pjax, т.е. ПОСЛЕ тега Pjax::begin, то можно кликнуть иконку даты, выбрать дату, данные отфильтруются. Потом ещё раз нажать, выбрать дату, отфильтруются и т.д.
  • Если инициализацию переменной $columns поместить за Pjax, т.е. ДО тега Pjax::begin, то можно выбрать дату только первый раз. После перезагрузки таблицы клик по иконкам не вызывают никаких событий. Просто мертвы.

Да, JS отваливается после перезагрузки контента. Да, можно это починить либо поместив $columns внутрь тега Pjax или после перезагрузки таблицы выполнить js код $('#w0-kvdate').kvDatepicker(window.kvDatepicker_33d8ead7); для перезапуска пикера.


Основной вопрос: почему такая магия происходит? Почему позиция переменной в конкретном выше коде PHP на сервере каким-то образом влияет на поведение JS? Я понимаю, если бы происходил echo переменной, а pjax буферизировал бы этот вывод и выводил после навешивания слушателей в JS. Но здесь всего лишь меняется позиция определения переменной. Как влияет? Почему перестаёт работать?


Ответы (1 шт):

Автор решения: phpBear

Все очень просто. Когда Вы выносите Columns за pjax, а следовательно и подключаемый в нем DatePicker, - то все подгружаемые для его работы js-скрипты подключатся перед </body>.

<html>
<head>
..тут подключаются .css
</head>
<body>

<script src=""></script>
</body>
</html>

И все css-селекторы в них прописаны на конкретные классы.

var initDPRemove = function () {
}, initDPAddon = function () {
};
(function ($) {
    "use strict";
    $.fn.kvDatepicker = $.fn.datepicker.noConflict();
    initDPRemove = function (id, range) {
        var $id = $('#' + id), $el = $id.parent(), $input;
        $el.find('.kv-date-remove').on('click.kvdatepicker', function () {
            if (range) {
                $el.find('input[type="text"]').each(function () {
                    $(this).kvDatepicker('clearDates').trigger('change');
                });
            } else {
                $el.kvDatepicker('clearDates');
                $input = $el.is('input') ? $el : $el.find('input[type="text"]');
                $input.trigger('change');
            }
        });
    };
    initDPAddon = function (id) {
        var $id = $('#' + id), $el = $id.parent(),
            pickers = '.input-group-addon:not(.kv-date-picker):not(.kv-date-remove)' +
                ',.input-group-text:not(.kv-date-picker):not(.kv-date-remove)';
        $el.find(pickers).each(function () {
            var $addon = $(this);
            $addon.on('click.kvdatepicker', function () {
                $el.kvDatepicker('hide');
            });
        });
        $el.find('.input-group-addon.kv-date-picker').on('click.kvdatepicker', function () {
            $id.focus();
        });
    };
})(window.jQuery);

Как Вы сами писали - после того как сработает pjax все bind на классы отвалятся т.к они по сути пропадут из DOM, а потом снова туда добавятся, но уже без bind. А вот если Вы вставите Columns после инициализации Pjax то все необходимые для его работы js-скрипты будут подключаться заново после каждой подгрузки содержимого pjax т.к <script scr="></script> будет прописан внутри pjax-контейнера, а соответственно инициализация datepicker будет вызвана снова и на все описанные в js-скрипте классы снова будет навешан bind.

Так что либо Вы все же перенесите $columns внутрь pjax - либо перепишите kartik-овский js на bind на body :)

$('body').on('click', '...', function(){
});
→ Ссылка