Основы Ajax
Ajax — это метод асинхронного запроса к серверу. Текущая страница html с помощью скрипта обращается к серверу с определенным вопросом, получает ответ и что-то с ним делает. Обычно — вставляет результат в страницу.
Итак, пишем простейший сниппет для получения запроса:
Тут все очевидно: сниппет ловит ajax запросы (а мы все делаем через jquery, который любезно шлет серверу заголовок HTTP_X_REQUESTED_WITH), проверяет, задано ли действие и пытается дать для него ответ.
Пару слов о прерывании парсера. Этот метод я придумал сам, и мне кажется, он гораздо удобнее, нежели использование отдельного php файла.
Лично мне нравится, что мои сниппеты в зависимости от запроса могут работать и через ajax, и просто при обычной загрузке, не завися ни от кого.
Классический же метод состоит в том, чтобы завести отдельный скрипт на сервере, который будет принимать все ajax запросы, и отвечать на них.
Или создать отдельную страницу, сделать к ней пустой шаблон, запихать туда опять же, один сниппет и прописывать в нем все методы ответов.
В общем, решайте сами, как вам больше нравится, статья моя — пишу как делаю я.
Конечно, мы будем использовать jQuery. Скрипт просто в теле страницы.
Всего несколько строчек кода и вы можете использовать асинхронные запросы.
Дальше нужно набивать новые методы в сниппет (вызов wayfinder, например), расставлять ссылки по страницам и развешивать обработчики событий на них.
Можно добавить к ссылке новый атрибут data-update="" и писать туда имя элемента для обновления. А при получении ответа вставлять его не в #result, как железно забито сейчас, а в указанный элемент. Тогда вы одними ссылками можете сделать сайт полностью на ajax.
Чуть изменить js скрипт и ссылку попробуйте сами.
Надеюсь, теперь, принцип ясен.
Как это сделать?
Итак, пишем простейший сниппет для получения запроса:
<?php
// Откликаться будет ТОЛЬКО на ajax запросы
if (empty($_SERVER['HTTP_X_REQUESTED_WITH']) || $_SERVER['HTTP_X_REQUESTED_WITH'] != 'XMLHttpRequest') {return;}
// Сниппет будет обрабатывать не один вид запросов, поэтому работать будем по запрашиваемому действию
// Если в массиве POST нет действия - выход
if (empty($_POST['action'])) {return;}
// А если есть - работаем
$res = '';
switch ($_POST['action']) {
case 'helloWorld':
$res = 'Hello World!';
break;
// А вот сюда потом добавлять новые методы
}
// Если у нас есть, что отдать на запрос - отдаем и прерываем работу парсера MODX
if (!empty($res)) {
die($res);
}Тут все очевидно: сниппет ловит ajax запросы (а мы все делаем через jquery, который любезно шлет серверу заголовок HTTP_X_REQUESTED_WITH), проверяет, задано ли действие и пытается дать для него ответ.
Пару слов о прерывании парсера. Этот метод я придумал сам, и мне кажется, он гораздо удобнее, нежели использование отдельного php файла.
Лично мне нравится, что мои сниппеты в зависимости от запроса могут работать и через ajax, и просто при обычной загрузке, не завися ни от кого.
Классический же метод состоит в том, чтобы завести отдельный скрипт на сервере, который будет принимать все ajax запросы, и отвечать на них.
Или создать отдельную страницу, сделать к ней пустой шаблон, запихать туда опять же, один сниппет и прописывать в нем все методы ответов.
В общем, решайте сами, как вам больше нравится, статья моя — пишу как делаю я.
Страница и скрипт
Конечно, мы будем использовать jQuery. Скрипт просто в теле страницы.
<!-- Наш сниппет, при обычной загрузке он ничего не делает -->
[[!Ajax_test]]
<!-- Подключаем jquery с сервера Яндекса -->
<script type="text/javascript" src="http://yandex.st/jquery/1.7.1/jquery.min.js"></script>
<!-- Наш скрипт запроса и обработки -->
<script type="text/javascript">
$(document).ready(function() {
// Вешаем обработчик события "клик" на все ссылки с классом ajax_link
$('a.ajax_link').click(function() {
// Берем действие из атрибута data-action ссылки
var action = $(this).data('action');
// Ajax запрос к текущей страницы (а на ней наш сниппет) методом post
$.post(document.location.href, {action: action}, function(data) {
// Выдаем ответ
alert('Запрос успешно выполнен')
$('#result').html(data);
})
// Не даем ссылке кликнуться - нам же не нужна перезагрузка страницы?
return false;
})
})
</script>
<!-- Ссылка с нужным классом и data - атрибутом, с действием -->
<a href="#" data-action="helloWorld" class="ajax_link">Привет, мир!</a>
<!-- html элемент для вставки ответа от php -->
<div id="result"></div>Можно копипастить в контент страницы.Итог
Всего несколько строчек кода и вы можете использовать асинхронные запросы.
Дальше нужно набивать новые методы в сниппет (вызов wayfinder, например), расставлять ссылки по страницам и развешивать обработчики событий на них.
Можно добавить к ссылке новый атрибут data-update="" и писать туда имя элемента для обновления. А при получении ответа вставлять его не в #result, как железно забито сейчас, а в указанный элемент. Тогда вы одними ссылками можете сделать сайт полностью на ajax.
Чуть изменить js скрипт и ссылку попробуйте сами.
Надеюсь, теперь, принцип ясен.
Комментарии: 86
Авторизуйтесь или зарегистрируйтесь, чтобы оставлять комментарии.
// Берем действие из атрибута data-action ссылки
var action = $(this).data('action');
Ведь по идее .data('data-action') надо запрашивать судя по описанию функции
в чем фокус? ))
Я не профи в программировании и просил пояснить работу функции.
Я первым делом полез посмотрел спецификацию по функции .data('name') в таком случае вернется значения параметра нейм.
А по сути в коде возвращается событие
те action выходит как зарезервированный в функции параметр или что?
Извиняюсь за глупые вопросы
Есть такой параметр data, через тире указывается его имя, а через равно — значение.
То есть, data-action=«getList» получается в jQuery как
var action = $('selector').data('action');
Вот и все.
…
case '5':
$params = array();
$start = 1;
$params[«startId»]=$start;
$res = $modx->runSnippet('Wayfinder', $params);
У меня возвращает пустое значение.
Спасибо.
Вывести результат то не забыли?
echo $res; die;
«Ответ сервера» формируется в сниппете с помощью die($res), и, по видимому, подхватывается методом $.post() автоматически.
А как этим способом обратиться к двум разным скриптам на одной странице?
Т.е. как различить ответ сниппета А и сниппета Б?
Ваши 2 разных скрипта должны реагировать на 2 разных action — для того оно и надо.
Где-то Уважаемый Василий об этом писал и пример обрыва парсера тоже присутствовал.
Хотелось бы привести пример:
Воспользовавшись сниппетом getResourceField вывести данные поля нужного ресурса
Код сниппета ajax:
Я создал отдельно ресурс в корне контекста, под названием ajax и соответствующим псевдонимом, он доступен по адресу mysite.ru/ajax.html, содержащий:
Вероятно чтобы «не путался под ногами» вызов сниппета и централизовать адрес ajax запросов. На всякий случай задал пустой шаблон и, само собой, скрыл для меню.
Код в теге HEAD используемого для примера шаблона:
Код в теге BODY, в любом удобном месте, используемого для примера шаблона:
При загрузке страницы с заданным шаблоном, используемым для примера, в тег div, под идентификатором results, произведётся асинхронная загрузка содержимого поля content ресурса с ID 56.
Я в последних разработках обращаюсь к специальному файлу, который запускается в MODX_API_MODE, но там есть свои заморочки.
соответственно при аякс-обращении сначала выполнятся будет сниппет и либо переключать переменную шаблона (в этом месте у меня зациклился мозг), либо выдавать [[*content]]
и завершать работу парсера, но тут тоже нерабочий быдлокод вышел в итоге =(
в эту сторону можно как то двигаться?
2. При твоём варианте, шаблон уже загружается, значит ты ничего не выигрываешь. Поэтому, либо плагин, либо файл.
Ну, либо делай как в заметке и не парься. Там работа обрывается командой die() — и ничего кроме ответа на Ajax не выводится.
Со всем вроде разобрался, но, как водится, нашел куда упереться — прошу помощи:
При активации функции (ссылка class=«ajax_link»), возвращается список ссылок class=«ajax_link».
А они работать никак не хотят:( То есть все ссылки, которые были в момент первой загрузке страницы — работают, а новые — не хотят.
Не могли бы подсказать, что это может быть за болячка?
Заранее благодарен,
Дмитрий.
После появления, кажется jQuery 1.7 нужно использовать функцию on():
При таком обработчике все ссылки будут проходить через него, независимо от их происхождения.
Т.е. вот так
Но так же можно использовать return false; в конце функции, потому что e.preventDefault(); не во всех браузерах правильно срабатывает
Лучше уж сферическое «e.preventDefault(); не во всех браузерах правильно срабатывает», чем долгий и нудный поиск бага на тему — почему же закрывается js-модальное окно или кастомный комбобокс…
Кстати, лично вы встречали какие-либо проблемы при использовании e.preventDefault()? Я лично нет (даже в ишаках, включая 7й), хотя верстаю много и (возможно) профессионально.
Вот в этой статье об это подробно рассказано bolsterweb.com/2011/01/javascript-e-preventdefault-is-not-return-false/
Правильно надо так:
Заработало:)
Василий подскажи, а как можно реализовать в твоем сниппете (в статье), чтобы сработало перенаправление на другую страницу, по типу:
у меня в итого приходит в страницу через ajax вызов страницы с ID = 1.
Голову сломал как оборвать работу ajax сниппета и перенаправить пользователя на страницу.
Как такое можно сделать?
Я могу повесить на success методе в ajax window.location на страницу нужную, но хочу серверное решение.
Это фоновый запрос от тебя, который возвращает браузеру ответ от сервера. При этом та страница, на которой ты находишься, ничего не делает, просто ждёт.
Отсюда вывод — твоя задача решается только через javascript.
Но не нужно расстраиваться, ведь любое перенаправление юзера — это просто команда браузеру перейти на другу страницу. Что через javascript, что через заголовки от php.
То есть, тут вообще нет «серверного решения», если вдуматься.
Прочитал, да все верно говоришь. Тогда не буду извращаться больше, сделаю через window.location.
1. вызываю Ditto — вывод есть, но в шаблоне есть конструкция с использованием сниппета If и соответственно его вызов не отрабатывается, как это полечить?
2. Фильтрация реализована через сниппет, который обрабатывает url (catalog.html/?f=man) и формирует строку для параметра &filter. Соответственно фильтрация тоже не работает.
есть ли решение данных проблем (особенностей)
заранее спс.
1. Нужно самостоятельно пропарсить результат, в Revo это делается так:
2. Насколько я понимаю, обрабатывается не url, а параметры в url, переданные в $_GET. Соответственнл, нужно немного изменить сниппет, чтобы он понимал параметры не только оттуда.
Советую задать эти вопросы камрадам с modx.im
1. Буду смотреть в сторону парсинга…
Т.е как у меня полчилось:
Снипет ajax
Без $result = $modx->parseDocumentSource($result); у меня внутри чанка Ditto (&tpl) выводило неотпрарсенные сниппеты, [+id+] и тд.
А так всё работает) Я счастлив) В принципе теперь у меня почти достаточно знаний что-бы делать полноценные ajax сайты на Evo.
Нарыл кстати это тут www.liveinternet.ru/journalshowcomments.php?jpostid=223127750&journalid=1999074&go=next&categ=0
это
Я 3й раз натыкаюсь на эту статью и только сейчас дошла основная идея! Гениально!
Я относительно зёлёный в этих вопросах, тяжко вникать в чужой код, Вы случайно не помните по этому-же принципу работаю ajaxserach в эво и shopkeeper или там сама идея реализации ajax другая?
Ну а про shopkeeper ничего не скажу — не знаю.
сама страница с вызовом снипета:
43 ресурс там вызов снипета, вот его код:
вопрос — при таком вызове у меня не работает параметр offset, как мне сделать смещение для обновления страницы при пагинации?
спасибо!
Смотри, как работает пагинация в фильтре тут.
Какая то загадка. Полдня уже мучаюсь.
Пока он отправляется на сервер, скрипт работает дальше, и переменная переопределится уже после второго алерта, когда придёт ответ.
Нужно или засунуть весь код, работающий с переменной в каллбэк, или делать синхронный запрос (не советую).
Если ошибки нет, то возвращаю пустую строку ($res=''). И вот тут _опа. В контейнер почему-то пишется вся страница:
Подскажи, как правильно вернуть пустое значение.
Инициализирую переменную:
При клике на ссылку посылаю ajax
В сниппете меняю переменную
Проверяю, $_SESSION['var'] — все равно равна 1. Не понимаю, это же глобальный массив.
Если в сниппете поставить
Ajax post возвращает 5. Но $_SESSION['var'] не меняется.
Видимо есть какое-то кодовое слово, чтобы заставить $_SESSION['var'] измениться.
Видимо, есть какая-то тонкость, которая ускользает от моего неопытного взгляда.
Ругается только на
У тебя, может, какой-то php-apc работать не дает? Попробуй добавить перед die
П.С. Я на Timeweb разрабатываю, значит у них чего-то перекручено.
П.П.С. Еще вопросик по безопасности сессий — злоумышленник может подменить значение $_SESSION переменной?
Насколько я знаю, сессии абсолютно безопасны, но их можно увести, узнав идентификатор, например через XSS на сайте.
Тут уже лучше Евгения расспрашивать.
Очень удобное решение, работает отлично!
Решил организовать загрузку ресурсов (целиком) в целевой #content следующим образом:
ajax.php (перехватывает id запрашиваемого документа из атрибута ссылки «data-rid»):
JS-обработчик:
Но возник вопрос с работой кнопки истории Назад. Не подскажите в каком направлении разумнее всего копать? (пробовал history.js, не до конца понял как связать все в одиное целое)
Пытаюсь вывести через ajax сниппет (т.е изначально сниппета на странице нет, он выводится по срабатыванию события). Сниппет выводится, но текстом, парсер видимо его не обрабатывает.
Если меняю в коде
то выводится целая страница в странице, вместе с обработанным сниппетом.
1. Если я правильно понял, то парсер заново обрабатывает всю страницу, поэтому и получается страница в странице?
2. Возможно ли сделать так, чтобы парсер обрабатывал только вновь вставленный сниппет?
Для решения вы можете вынести код сниппета в отдельный файл (ajax/name.php):
И при помощи jQuery на срабатывания нужного события запрашивать/возвращать результат:
И скрипт с частью страницы, помещен в чанк ajaxscr, на странице выводится через чанк
Вывод на странице
[[!Ajax1]]
[[$ajaxscr?]]
Спасибо страница перестала дублироваться, но обратил внимание на другую проблему.
Форма TicketForm не работает, ничего не отправляет, не добавляет фото (при клике ничего не происходит), рядом с «Выберите файл» появились «0/0 0%», при нажатии кнопки «на проверку» (даже с пустой формой) просто перезагружается страница
то данная форма работает.
Форма выведенная через ajax не работает
В случае же с аякс-загрузкой их подключение не происходит.
Подумал, что что-то пропустил и вывел на эту же страницу [[!TicketForm?]] для подключения скриптов, ситуация не изменилась. Стандартная форма работает, форма через ajax нет. Еще обратил внимание, что у формы через ajax нет (не выведены) элементов форматирования текста: B,I…
Формы отличаются
1. Форма «Содержимое» через ajax
2. «Форма Содержимое» стандартное
Но даже если все это добавить в форму выводимую через ajax, кнопки появляются, но не работают. Где-то внутри еще есть подключение скриптов.
Я защел в тупик, куда копать дальше
+ формируют массив TicketsConfig.
+ (опционально) скрипты редактора MarkitUp.
Вы можете попробовать подгружать их самостоятельно и запускать их внутренние элементы инициализации через $(document).ajaxStop. Плюс формировать конфигурационный массив самостоятельно.
UPD: Но я вас заверяю — без глубоких знаний php+js оно того вообще не стоит и грозит очень серьезно переписать исходный сниппет.
Как сделать чтобы сниппет подгружал данные каждые 5-15 сек. (Любые данные из JSON)
Пример кода сниппета:
Точнее так, выводится фильтр со значениями для фильтрации, а товаров нет.
Решил добавить фильтр через выпадающий список по годам.
Обрабатываю акцию вот так:
результат приходит правильно, но в шаблоне не обрабатываются феном теги, а модикса обрабатываются ({dt_item} — не работает, [[+dt_item]] — работает).
В настройках pdoTools все включено.
Шаблон с моими феном тегами tpl.full:
Напомню: изначально феном теги обрабатываются. Страница загрузилась, все хорошо. Выбираю из выпадающего списка год, запрос уходит куда нужно, скрипт обрабатывается, но феном теги перестают работать.
Выходит что вызывать свой сниппет в сниппете нельзя?
Или что еще нужно сделать чтобы
$modx->runSnippet('HistoryMod', $params);
начал работать с тегами Fenom?