[AjaxSnippet] Запуск сниппетов через Ajax

Хочу поделиться простеньким и удобным решением, написанным только что - универсальный запуск сниппетов через Ajax.

Логика работы очень простая:

  1. Вызываете AjaxSnippet на любой странице сайта, с указанием имени нужного сниппета и параметров.
  2. Сниппет выдаёт в текущую страницу пустой блок с прелоадером и регистрирует ajax запрос.
  3. После загрузки страницы этот запрос уходит на сервер и ответ помещается в приготовленный блок.

Прототип этой идеи я уже давно описывал.

Теперь вы можете легко ускорить загрузку своего сайта - просто оборачивайте не особо важные сниппеты в AjaxSnippet и они дозагрузятся через ajax:

[[!AjaxSnippet?
    &snippet=`pdoResources`
    &parents=`0`
    &tpl=`@INLINE <p>[[+idx]]. <a href="[[+link]]">[[+pagetitle]]</a></p>`
    &useWeblinkUrl=`1`
]]

Всего 61 строка кода, три параметра, никаких чанков, дополнительных скриптов или стилей. По умолчанию выводится вот такой прелоадер.

После вывода результата вызывается jQuery событие as_complete, куда передаются полученные данные и вы можете что-то еще с ними сделать.

$(document).on('as_complete', document, function(e,d) {
    console.log(d);
});

Если сниппет вызывается через пагинатор - то помимо результата в output, вы получите еще 2 значения: pagination и total. Можно сделать ajax пагинацию.

Пакет в нашем репозитории. Исходный код на GitHub.

Посмотреть в работе можно прямо здесь - блок с последними комментариями и тикетами теперь грузится при помощи AjaxSnippet.

← Предыдущая заметка
[Tickets] 1.3.0-beta Сниппет TicketMeta и рейтинги
Следующая заметка →
[Tickets] 1.3.0-beta Анонимные комментарии
Комментарии (38)
Мордынский Николай
30.01.2014 12:03

Насколько я понял получается что, сначала пользователю выдается готовая страница при этом единовременная нагрузка на сервер меньше (потому что отпадают запросы в базу для генерации к примеру тех же комментариев). И дополнительно после загрузки страницы происходит подгрузка по AJax. Тема походу должна ускорять нагруженные проекты.

Мордынский Николай
30.01.2014 12:27

Сейчас Василий закидает меня дровами или чем по хуже.

Есть 1 очень важное НО если вы ориентируетесь на СЕО то поисковая система не увидит контент подгруженный после загрузки страницы. Вот тут можно посмотреть( pr-cy.ru/simulator ) с точки зрения робота , на сайте вместо прямого эфира размещен Этот самый прелоадер

Но плагин супер ))) им по идее можно грузить не важные для поисковых систем элементы сайта. Или вобще все если вы не ориентированы на поисковую выдачу

Чикин Артур
30.01.2014 13:54

Тут не готовое решение, а всего лишь болванка для твоей реализации.

OnFoxПеретягин Илья
30.01.2014 14:43

Это наоборот хорошо, я специально убираю элементы страницы, которые не хочу показывать поисковику, только вот я это делал через ж..., а тут готовый сниппет, надо будет по разбираться с ним. Быстро посмотрев могу сказать только одно неудобство, он подгружает непосредственно вызов других сниппетов, а хорошо бы скрывать целые блоки кода, но сниппет же не для сеошников писался ))).

bezumkinВасилий Наумкин
30.01.2014 15:05

Так ты напиши свой сниппет, который будет выводить нужные тебе блоки кода - и вызывай его.

Ну и для многих сниппетов можно указывать &tplWrapper - чанк обертку для заворачивания результатов.

Пропиши в нем все нужное, а для результатов оставь [[+output]] и получишь через ajax готовый блок со всеми наворотами.

Виталий Князь
31.01.2014 08:05

Фигня все это

bazmasterВасилий Столейков
30.01.2014 18:30

&totalVar у pdoResources не срабатывает. Вызов примерно такой:


[[!AjaxSnippet:default=`Ура! Тут ничего нет!`?
    &tpl=`tpl.example.empty` 
    &limit=`4` 
    &parents=`5` 
    &includeContent=`1` 
    &includeTVs=`code` 
    &processTVs=`1` 
    &where=`{"content":""}` 
    &showUnpublished=`1`
    &totalVar=`totalEmpty`
    &sortby=`RAND()`
]]
[[+totalEmpty]]
bezumkinВасилий Наумкин
30.01.2014 18:34

Попробуй подумать, когда обрабатывается плейсхолдер и когда ты получаешь данные от сниппета.

А потом попробуй внимательно прочитать заметку, обращая снимание на javascript событие as_complete и

Если сниппет вызывается через пагинатор — то помимо результата в output, вы получите еще 2 значения: pagination и total.

То есть, total и html с пагинацией ты получаешь в javascript и нужно его куда-то вставить на странице.

shadowВладимир
31.01.2014 13:34

Доброго дня! Спасибо за новый мастхэвчик! С pdoResources все работает чудесно. С eventsCalendar2 подружить "нахрапом" не удалось :) А очень бы хотелось календарик подгружать в последнюю очередь.

bezumkinВасилий Наумкин
31.01.2014 14:29

Для календаря нужно отдельно зарегать его скрипты и стили, тогда может и заработает.

Александро
01.02.2014 08:32

Единственное стоит отметить, что если перед вызовом AjaxSnippet будет стоять "тяжелый" вызов не кешированного сниппета (Ну допустим), то он выполнится 2 раза. А если AjaxSnippet будет несколько вызовов, то и все сниппеты что находятся выше в шаблоне будут выполняться это число раз +1, что увеличит нагрузку на сервер.

Мне кажется лучше всего использовать плагин, который будет обрабатывать сниппет с параметром ajax=itemlist (Перед обработкой парсером сниппетов), запрос при этом должен быть $_POST['action']='itemlist':


[[!pdoResources?
    &parents=`0`
    &tpl=`@INLINE <p>[[+idx]]. <a href="[[+link]]">[[+pagetitle]]</a></p>`
    &useWeblinkUrl=`1`
    &ajax=`itemlist`
]]

Василий как всегда молодец, спасибо за отличный сниппет!

bezumkinВасилий Наумкин
01.02.2014 08:36

Подумаю про плагин, спасибо.

bezumkinВасилий Наумкин
01.02.2014 09:02

Добавил плагин, можно обновляться.

У меня на сайте отклик ускорился раза в 2.

Александро
01.02.2014 10:06

Можно пойти еще дальше, добавить параметр &mode который может принимать параметры:

0 - обычный режим работы, то есть результат работы показывается сразу, но мы можем обновлять данные этого блока по ajax 1 - режим работы как сейчас, загружать по готовности страницы 2 - режим работы при котором мы дополнительно указываем параметр

&tplAjaxLink=`@INLINE <a href="[[+key_submit]]">Показать этот блок</a>`

при первоночальной загрузке показывается tplAjaxLink, при клике по которой подгружается уже результат работы скрипта.

LEONesoПавел Левин
01.02.2014 20:05

А как скрыть прелоадер?

LEONesoПавел Левин
01.02.2014 21:47

Собственно разобрался, только вручную, никаких параметров.

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

Пример того, о чем я писал и что хотел подгружать:

asxАлександр Котлов
02.02.2014 14:31

Василий, а логика чанка-обертки как в pdoResources или другая? У меня он выводится даже если сниппет ничего не вернул. Так и надо?

bezumkinВасилий Наумкин
02.02.2014 15:49

Прочитай еще раз принцип работы.

При загрузки страницы сниппет не выполняется. То есть, сниппета как бы нет, он ничего не возвращает.

А вот когда страница загружена, уходит ajax запрос и тогда уже можно говорить о работе сниппета, и о том, что он вернул.

В этом и смысл - выполнить сниппет после загрузки страницы. А место под его ответ готовится всегда.

asxАлександр Котлов
02.02.2014 16:47

Понял. Принцип я понимаю, просто думал что там проверка есть, тк она туда прям просится) Ну раз нет - выкручусь по другому)

bezumkinВасилий Наумкин
02.02.2014 18:29

Проверка на наличие сниппета есть, но сам он не запускается.

asxАлександр Котлов
02.02.2014 23:34

Я про проверку на результат работы сниппета. Логично было бы не показывать обертку, пока сниппет ничего не вернул, или потом ее сразу скрывать если . Но это такие мелочи)

shadowВладимир
10.02.2014 20:25

tagLister так славно "спрятался" в AjaxSnippet, что вдвое быстрее стала главная загружаться)) Спасибо Василий!

bezumkinВасилий Наумкин
11.02.2014 04:44

На здоровье!

Чикин Артур
12.02.2014 07:02

Щикарно:) Повесил его на TwitterX и время первой загрузки не из кэша сократилось на 2 скунды:)

P.S TwitterX ждет ответ от Twitter`а и из за этого страница загружается на 1-2 секунды дольше.

Kirill Bedin
11.03.2014 08:37

Василий, привет. Не могу понять зачем в $post передается as_action: "'.$key.'". За что отвечает этот as_action?

Kirill Bedin
11.03.2014 12:51

Разобрался, данный параметр используется в плагине.

Влад Крестич
08.07.2014 08:17

Добрый день, можно ли при отработке сниппета, получать какой-то оригинальный id операции? Поясню, например, на странице идет вызов пяти иногда трех ajaxsnippet-ов (используются условия). После отработки сниппетов "результаты" обрабатываются плагинами jquery (собирается меню/табы и т.д.) Инициализация этих плагинов должна проходить не как обычно в $(document).ready, а по событию "ajaxComplete" соответственно, каждый плагин проинициализируется столько раз, сколько было закончено аякс запросов. Думал сделать переменную и увеличивать по инкременту с каждым событием ajaxComplete и просто сделать условие, если эта переменная равна количеству всех запросов то делать инициализацию всех плагинов, но это во-первых не очень красиво для пользователя, который в первое время видит в "разобранном" виде некоторые блоки, пока не отработают все запросы, да и во-вторых как я писал, не известно сколько запросов будет идти на странице, у одного товара 3, у другого - 5. А дальше на странице еще по аяксу добавляется товар в корзину, отправляются комменты, заявки и т.д. Поэтому хотелось бы иметь какой-то id по окончанию выполнения каждого ajaxsnippet, чтобы потом точно перебирать эти id и для каждого выполнять соответствующую инициализацию плагинов. Василий, подскажите, как это сделать?

bezumkinВасилий Наумкин
08.07.2014 08:18

В заметке же написано:

После вывода результата вызывается jQuery событие as_complete, куда передаются полученные данные и вы можете что-то еще с ними сделать.

Если сниппет отдаст какой-то id, то его можно получить в jQuery при этом событии.

$(document).on('as_complete', document, function(e,d) {
    console.log(d);
});
Влад Крестич
08.07.2014 08:36

какую из переменных объекта "d" вы бы использовали? key всегда разный генериться, snippet вывода везде один и тот же, а output выводиться по разным шаблонам и его парсить будет очень сложно

bezumkinВасилий Наумкин
08.07.2014 08:39

Ну раз "очень сложно", то больше ничем не могу помочь.

Влад Крестич
08.07.2014 09:31

спасибо, легче уж переписать сниппет, чтобы можно было по-человечески подавать в него параметр с нужным мне id и выводить в его в этот объект "d" и "перенести" прелоадер к себе на сервер.

Влад Крестич
08.07.2014 08:45

кстати, сегодня прелоадер, используемый в ajaxsnippet с вашего сервера не хочет грузиться.


Failed to load resource: the server responded with a status of 404 (Not Found) 
https://file.modx.pro/files/8/3/3/8331d0647f1caccaa2d134de73d47bbb.gif 

Зачем вообще вы так сделали с сниппете? бедный ваш сервер...

Влад Крестич
08.07.2014 08:33

Видел, что можно по окончанию запроса получать объект "d" в котором какой-то ключ операции (генерируется всегда разный), весь вывод и название сниппета для вывода. Это получается только надо "рыться" в output и исходя из его содержимого делать то что я хочу...не очень круто ведь содержимое output не выводится по одному шаблону

Александр
30.07.2014 18:09

Здравствуйте. Вопрос вот в чем: На странице в боковой колонке был реализован вызов getResources для отображения списка самых просматриваемых тем. Решил выводить через AjaxSnippet, но после выполнения сниппета не отрабатывает {%hp-[[+id]]%}. Вернее не отрабатывает сниппет HPCount, так как пользователю выводится {%hp-123%}. Вероятно нет инициализации HPCount вызываемом в футере. Вызов [[!HPCount]] в чанке шаблона getResources результата тоже не дал. Может кто посоветует как выйти из этой ситуации?

[[AjaxSnippet?
&snippet=`getResources`
&parents=`.....`
&tpl=`rating-lst` 
&showHidden=`0` 
&includeTVs=`LikeDislike` 
&tvPrefix=``
&sortbyTVType=`integer`
&sortbyTV=`LikeDislike`
&limit=`5`
&as_mode=`onload`
]]

чанк rating-lst

.... Просмотров: {%hp-[[+id]]%} .....
Alex Zhuravlev
23.08.2014 05:21

Василий привет. Спасибо за отличные компоненты к modx и их описания . Хочу вывести снипет login. Делаю так


[[!AjaxSnippet?
    &snippet=`login`
    &loginTpl=`myLoginChunk`
    &placeholderPrefix=`login.`
    &validate=`nobot:blank`
    &loginResourceId=`33`
    &logoutResourceId=`6`
    &loginMsg=`Войти`
]]

и сам чанк с формой


<form action="[[~[[*id]]]]" method="post">
    <div class="auth_error">[[!+errors:notempty=`<div class="alert alert-warning">[[!+errors]]</div>`]]</div>
    <div class="cart-block">
        <input type="hidden" name="nobot" value="" />
        <div class="cart-block-ins">
            <span class="sub-title">Ваш e-mail</span>
            <input id="username" name="username" class="input-box" type="email" placeholder="Email при регистрации..." required />
        </div>
        <div class="cart-block-ins">
            <span class="sub-title">Ваш пароль</span>
            <input id="password" name="password" class="input-box" type="password" placeholder="Пароль..." required />
        </div>
            <span><a href="remember">Забыли пароль?</a></span> &nbsp&nbsp
            <span><a href="register">Еще не зарегистрированы?</a></span><br />
        <div class="reg-in-site">
            <input class="btn-th" type="submit" name="Login" value="[[+actionMsg]]" />
        </div>
    </div>
</form>

В таком исполнении форма появляется? Ввожу правильные или неправильные данные, login-pass вижу ромашку, далее перезагрузка страницы. В консоли хрома никаких ошибок нет. Сама форма логина исправно работает без AjaxSnippet. В чем моя ошибка и как нужно правильно реализовывать?

Alex Zhuravlev
23.08.2014 16:36

Сергей, спасибо за ссылку, видел ее и реализовал по ней. Для себя хотел попробовать реализовать AjaxSnippet от Василия, посмотреть как оно будет работать. Я уверен что все должно работать но в манах есть только один пример.

На хабре писал Василий

И в AjaxSnippet, и в AjaxForm можно указать любой сниппет для работы, с произвольным кодом и функциональностью.

Alex Zhuravlev
03.09.2014 13:02

Василий, вы можете сказать почему не работает Ajaxsnippet + login

bezumkin
Василий Наумкин
04.07.2022 23:34
Что-то странное у тебя произошло: миграция есть, и вроде как выполнена, но таблицы при этом отсутств...
inetlover
Александр Наумов
03.07.2022 20:36
Василий, спасибо! Все понятно!
bezumkin
Василий Наумкин
02.07.2022 20:28
Спасибо, поправил!
bezumkin
Василий Наумкин
30.06.2022 03:58
Есть ли возможность формировать &quot;friendly URL aliases&quot;, используя аналог translit MODx? ...
bezumkin
Василий Наумкин
27.06.2022 03:32
Спасибо за исправления, очень выручаешь =) Но учитывая количество не описаных в заметке дополнительн...
bezumkin
Василий Наумкин
27.06.2022 03:10
что будет использоваться для вывода многоуровневого меню Посмотри как работают комментарии на этом ...
bezumkin
Василий Наумкин
25.06.2022 11:56
Поправил, спасибо!
bezumkin
Василий Наумкин
21.06.2022 01:58
onLoad(data) { this.total = data.total }, и onLoad({total}) { this.total = total }, В нашем случ...
bezumkin
Василий Наумкин
20.06.2022 14:01
Прекрасно тебя понимаю, я когда сам в этом разбирался - голова дымилась. Но зато теперь прямо-таки п...
bezumkin
Василий Наумкин
20.06.2022 09:30
Не надо, оно по умолчанию так - я просто чуть более подробно написал.