[СДЕЛАЙ САМ] Поиск с mSearch2 и SendIt без перезагрузки страницы и динамическими параметрами
Приветствую, думаю ни для кого не секрет, что mSearch2 не умеет показывать результаты поиска без перезагрузки страницы, а pdoPage не умеет «на лету» менять параметры. На своём сайте я захотел сделать морфологический поиск услуг без перезагрузки, с постраничной навигацией и возможностью выбирать категорию поиска. Ниже опишу чтобы для этого было предпринято.
1. Разметка
Для начала нам нужна форма для ввода запроса и выбора категории, блок для вставки результатов и блок для вставки пагинации. Выглядит это примерно так:
2. Сниппет-обработчик
Для обработки формы на сервере нужен сниппет:
После того как наш сниппет запустил mSearch2 и pdoPage нам нужно вывести результаты, для этого понадобится примерно такой JS
Этот код добавит запрос и родителя в get-параметры, что позволит делится ссылкой (@Дима Касаткин спасибо за идею), если в вызове pdoPage вы эти параметры укажете примерно вот так
4. Обработка переключения страницы
При переключении страницы нужно дополнительно отправлять на сервер выбранные параметры (запрос и родителя). Дл этого нужно изменить оригинальный JS pdoPage (assets/components/pdotools/js/pdopage.js). В методе pdoPage.loadPage в конце блока объявления переменных (после стр. 128) нужно добавить наши данные
На этом изменения в оригинальном JavaScript закончены. Отмечу, что править исходный файл не нужно, сделайте копию и измените системную настройку с путями к скриптам фронтенда.
5. Собственный коннектор
Поскольку на предыдущем шаге мы добавили в запрос новые параметры, нужно научить коннектор их обрабатывать. ДЛя этого я сделал копию родного коннектора и внёс изменения после 24 строки
В данный момент ведётся активная работа над MiniShop3 силами сообщества и руками @Николай Савин, поэтому призываю всех неравнодушных поддержать эту работу финансово.
1. Разметка
Для начала нам нужна форма для ввода запроса и выбора категории, блок для вставки результатов и блок для вставки пагинации. Выглядит это примерно так:
<form id="searchForm" data-si-form="searchForm" data-si-preset="search">
<label>
<input type="text" name="query" placeholder="Ключевые слова">
</label>
<div>
<select name="parent">
<option value="36">Выберите категорию</option>
<!-- вызов спиппета pdoResources -->
</select>
</div>
<button type="submit">Найти</button>
</form>
<div id="results">
<!-- вызов спиппета pdoPage -->
</div>
<div id="pagination">
<!-- пагинация -->
</div>
У меня за отправку формы отвечает сниппет SendIt, вы можете использовать тот, который вам больше нравится.2. Сниппет-обработчик
Для обработки формы на сервере нужен сниппет:
<?php
$_GET['query'] = $_POST['query'];
/*
тут должен быть массив параметров вызова pdoPage
я их получаю из файла с пресетами,
но это актуально только при использовании MigxPageConfigurator
*/
$params = include(MODX_BASE_PATH . $presetPath);
$catalogParams = $params[$presetName];
foreach ($catalogParams as $k => $v) {
$catalogParams[$k] = str_replace('#/', '@FILE chunks/', $v);
}
/*
устанавливаем параметры вызова из запроса
*/
$catalogParams['parents'] = (int)$_POST['parent'];
if ($_POST['query'] && strlen($_POST['query']) >= $catalogParams['minQuery']) {
$catalogParams['resources'] = $modx->runSnippet('mSearch2', ['parents' => (int)$_POST['parent'], 'limit' => 0, 'returnIds' => 1]);
}
/*
проверяем поменялся ли родитель с прошлого запроса
если поменялся значит это новая выборка и нужно перейти на первую страницу
*/
if ($_SESSION['liveSearch']['parent'] !== (int)$_POST['parent'] || $_SESSION['liveSearch']['query'] !== $_POST['query']) {
$_GET['page'] = 1;
}
/*
устанавливаем отступ
*/
if ((int)$_POST['current_page'] && (int)$_POST['current_page'] <= (int)$_POST['total_pages']) {
$params['offset'] = ((int)$_POST['current_page'] - 1) * $catalogParams['limit'];
}
/*
получаем плейсхолдеры сгенерированные pdoPage
*/
$html = $modx->runSnippet('pdoPage', $catalogParams);
$page = (int)$modx->getPlaceholder($catalogParams['pageVarKey'] ?: 'page');
$pagination = $modx->getPlaceholder($catalogParams['pageNavVar'] ?: 'page.nav');
/*
записываем параметры запроса в сессию
*/
$_SESSION['liveSearch']['resources'] = $catalogParams['resources'];
$_SESSION['liveSearch']['parent'] = $_POST['parent'];
$_SESSION['liveSearch']['query'] = $_POST['query'];
return $SendIt->success('', ['html' => $html, 'parent' => (int)$_POST['parent'], 'page' => $page, 'query' => $_POST['query'], 'pagination' => $pagination]);
3. Обработка ответа сервераПосле того как наш сниппет запустил mSearch2 и pdoPage нам нужно вывести результаты, для этого понадобится примерно такой JS
document.addEventListener('si:send:finish', async (e) => {
const results = document.querySelector('#results');
const pagination = document.querySelector('#pagination');
const url = window.location.href;
const params = new URLSearchParams(window.location.search);
e.detail.result.data.parent ? params.set('parent', e.detail.result.data.parent) : params.delete('parent');
e.detail.result.data.query ? params.set('query', e.detail.result.data.query) : params.delete('query');
if(e.detail.result.data.page ><code></code> 1){
params.set('page', e.detail.result.data.page);
}else{
params.delete('page');
pdoPage.keys[pdoPage.configs.page['pageVarKey']] = 1;
}
if(params.toString()){
window.history.replaceState({}, '', url.split('?')[0] + '?' + params.toString());
}else{
window.history.replaceState({}, '', url.split('?')[0]);
}
if(results){
results.innerHTML = e.detail.result.data.html;
}
if(pagination){
pagination.innerHTML = e.detail.result.data.pagination;
}
});
Этот код добавит запрос и родителя в get-параметры, что позволит делится ссылкой (@Дима Касаткин спасибо за идею), если в вызове pdoPage вы эти параметры укажете примерно вот так
{'!pdoPage' | snippet: [
'element' => 'msProducts',
'resources' => ('!mSearch2' | snippet: ['parents' => $.get.parent, 'limit' => 0, 'returnIds' => 1])?: '999999'
...
]}
Я привел примерный код, поскольку в моём вариант после загрузки происходит автоматическая отправка формы, при наличии сохранённых параметров.4. Обработка переключения страницы
При переключении страницы нужно дополнительно отправлять на сервер выбранные параметры (запрос и родителя). Дл этого нужно изменить оригинальный JS pdoPage (assets/components/pdotools/js/pdopage.js). В методе pdoPage.loadPage в конце блока объявления переменных (после стр. 128) нужно добавить наши данные
var query = wrapper.find('[name="query"]');
var parent = wrapper.find('[name="parent"]');
А после блока формирования параметров нужно добавить наши данные к нимif(query.length){
params['query'] = query.val();
}
if(parent.length){
params['parent'] = parent.val();
}
На строке 173 замените config['connectorUrl'] на путь к вашему коннектору (зачем он нужен читайте ниже).На этом изменения в оригинальном JavaScript закончены. Отмечу, что править исходный файл не нужно, сделайте копию и измените системную настройку с путями к скриптам фронтенда.
5. Собственный коннектор
Поскольку на предыдущем шаге мы добавили в запрос новые параметры, нужно научить коннектор их обрабатывать. ДЛя этого я сделал копию родного коннектора и внёс изменения после 24 строки
/*
если уже есть найденные ресурсы
значит нужно перейти на другую страницу
в другом случае надо перейти на первую страницу
*/
if ($_SESSION['liveSearch']['resources']) {
$scriptProperties['resources'] = $_SESSION['liveSearch']['resources'];
} else {
if ($_SESSION['liveSearch']['parent'] !== $_GET['parent'] || $_SESSION['liveSearch']['query'] !== $_GET['query']) {
$_GET['page'] = 1;
}
$scriptProperties['parents'] = $_SESSION['liveSearch']['parent'];
}
Вот и всё. Посмотреть как это работает можно тут.В данный момент ведётся активная работа над MiniShop3 силами сообщества и руками @Николай Савин, поэтому призываю всех неравнодушных поддержать эту работу финансово.
Поблагодарить автора
Отправить деньги