Обновление части шаблона Twig с помощью Ajax

Столкнулась с необходимостью обновить часть страницы, созданной в Twig, с помощью ajax-запроса. Как обновить страницу, используя шаблон, где есть готовый цикл, который я хочу снова использовать? В поиске готовых вариантов нашла всего один вопрос на StackOverflow и кучу кривых переводов той же страницы. Возможно, решение такое тривиальное? Или никто не занимается этим? Или мои навыки поиска решений далеки от идеала?
В любом случае, на будущее запишу своё решение.
Задача и код сильно упрощены, в моём проекте нужно было получать другие объекты.

Задача:
Каждые 10 секунд обновлять на странице данные: показывать 10 последних комментариев.

Алгоритм:

  1. Ту часть страницы, которую нужно обновлять, выделить в отдельный шаблон.
  2. При запросе обрабатывать этот отдельный шаблон и отправлять результат в ответе.

Я использую Symfony 4, и вот в контроллере есть страница, где выводятся последние комментарии:

Исходный код

1
2
3
4
5
6
7
8
9
public function commentsPage()
{
$comments = $this->getDoctrine->getRepository(Comments::class)
->findLastTen();
// метод findLastTen написать в CommentsRepository
return $this->render('comments_page.html.twig',[
'comments' => $comments,
]);
}

Её шаблон выглядит как-то так (очень упрощаю для примера):

1
2
3
4
5
6
7
8
9
10
{# comments_page.html.twig #}

{% extends 'base.html.twig' %}
{% block main %}
<ul>
{% for comment in comments %}
<li>{{ comment.text }}</li>
{% endfor %}
</ul>
{% endblock %}

При обновлении страницы последние комментарии будут обновляться. А мы хотим делать это без обновления страницы.

Новый twig-шаблон

Первым делом я выделю кусочек с комментариями в отдельный шаблон. (Лучшие практики: название файла с кусочком шаблона начинается с нижнего подчёркивания).

1
2
3
4
5
6
7
{# _last_comments.html.twig #}

<ul>
{% for comment in comments %}
<li>{{ comment.text }}</li>
{% endfor %}
</ul>

И изменю шаблон первоначальный:

1
2
3
4
5
6
{# comments_page.html.twig #}

{% extends 'base.html.twig' %}
{% block main %}
{% include '_last_comments.html.twig' %}
{% endblock %}

Новый php-код

Нужно добавить страницу, к которой будем делать ajax-запрос.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
/**
* @Route("/last-comments", name="last_comments", methods={"POST"})
*/
public function lastComments()
{
$comments = $this->getDoctrine->getRepository(Comments::class)
->findLastTen();

$lastComments = $this->renderView('_last_comments.html.twig',[
'comments' => $comments
]);

return new Response($lastComments);
}

JavaScript

Осталось добавить собственно запрос и повторять его.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
{# comments_page.html.twig #}

{% extends 'base.html.twig' %}
{% block main %}
<div class="js-last-comments">
{% include '_last_comments.html.twig' %}
</div>
{% endblock %}

{% block javascripts %}
{{ parent() }}
<script>
setInterval(function () {
$.ajax({
method: 'POST',
url: "/last-comments"
}).done(function (data) {
$('.js-last-comments').html(data);
});
}, 10000);
</script>
{% endblock %}