Почему вынесение переменной за 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 шт):
Все очень просто. Когда Вы выносите 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(){
});