Работа с JavaScript
В папке templates, создадим папку js, для хранения скриптов, а в ней два файла: comments.js и backend.js.
Добавим в файл backend.js следующий JavaScript код:
const getCookie = (name) => {
let cookieValue = null;
if (document.cookie && document.cookie !== "") {
const cookies = document.cookie.split(";");
for (let i = 0; i < cookies.length; i++) {
const cookie = cookies[i].trim();
// Does this cookie string begin with the name we want?
if (cookie.substring(0, name.length + 1) === name + "=") {
cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
break;
}
}
}
return cookieValue;
};
const csrftoken = getCookie("csrftoken");
В этом коде мы определяем функцию getCookie, которая принимает имя куки (cookie) и возвращает ее значение.
Эта функции проверяет, есть ли у нас сохраненные куки, и если да, то эти куки разделяются по символу ; и перебираются в цикле.
Для каждого элемента, функция проверяет, начинается ли ее строковое представление с имени куки, которое мы ищем. Если да, то значение куки декодируется с помощью decodeURIComponent и сохраняется в переменной cookieValue, после чего цикл прерывается.
В конце функция возвращает значение cookieValue. После этого, определяется переменная csrftoken, которая получает значение куки с именем csrftoken, вызвав функцию getCookie. Посмотреть в документации.
Теперь добавим в файл comments.js следующий JavaScript код для добавления комментариев:
const commentForm = document.forms.commentForm;
const commentFormContent = commentForm.content;
const commentFormParentInput = commentForm.parent;
const commentFormSubmit = commentForm.commentSubmit;
const commentPostId = commentForm.getAttribute('data-post-id');
commentForm.addEventListener('submit', createComment);
replyUser()
function replyUser() {
document.querySelectorAll('.btn-reply').forEach(e => {
e.addEventListener('click', replyComment);
});
}
function replyComment() {
const commentUsername = this.getAttribute('data-comment-username');
const commentMessageId = this.getAttribute('data-comment-id');
commentFormContent.value = `${commentUsername}, `;
commentFormParentInput.value = commentMessageId;
}
async function createComment(event) {
event.preventDefault();
commentFormSubmit.disabled = true;
commentFormSubmit.innerText = "Ожидаем ответа сервера";
try {
const response = await fetch(`/post/${commentPostId}/comments/create/`, {
method: 'POST',
headers: {
'X-CSRFToken': csrftoken,
'X-Requested-With': 'XMLHttpRequest',
},
body: new FormData(commentForm),
});
const comment = await response.json();
let commentTemplate = `<ul id="comment-thread-${comment.id}">
<li class="card border-0">
<div class="row">
<div class="col-md-2">
<img src="${comment.avatar}" style="width: 120px;height: 120px;object-fit: cover;" alt="${comment.author}"/>
</div>
<div class="col-md-10">
<div class="card-body">
<h6 class="card-title">
<a href="${comment.get_absolute_url}">${comment.author}</a>
</h6>
<p class="card-text">
${comment.content}
</p>
<a class="btn btn-sm btn-dark btn-reply" href="#commentForm" data-comment-id="${comment.id}" data-comment-username="${comment.author}">Ответить</a>
<hr/>
<time>${comment.time_create}</time>
</div>
</div>
</div>
</li>
</ul>`;
if (comment.is_child) {
document.querySelector(`#comment-thread-${comment.parent_id}`).insertAdjacentHTML("beforeend", commentTemplate);
}
else {
document.querySelector('.nested-comments').insertAdjacentHTML("beforeend", commentTemplate)
}
commentForm.reset()
commentFormSubmit.disabled = false;
commentFormSubmit.innerText = "Добавить комментарий";
commentFormParentInput.value = null;
replyUser();
}
catch (error) {
console.log(error)
}
}
Этот код реализует функционал добавления комментариев к статье на сайте, выполняя следующие функции:
- Создает переменные для хранения формы комментария, содержания, родительского элемента комментария, кнопки отправки и
IDстатьи.
- Назначает функцию
createCommentдля события отправки формы комментария.
- Функция
replyUserдобавляет обработчики события для кнопокОтветить, которые позволяют пользователю ответить на другой комментарий.
- Назначает функцию
replyCommentдля кнопкиОтветитькаждого комментария, чтобы ответить на комментарий.
- Определяет функцию
createCommentдля отправки данных формы комментария на сервер. Она используетfetch API, чтобы отправить POST запрос на сервер для создания нового комментария.
- Она также добавляет заголовки
X-CSRFTokenиX-Requested-Withс текущим значениемcsrftokenиXMLHttpRequest, соответственно.
- Далее мы получаем ответ от сервера в виде JSON, от представления
CommentCreateView, который добавляем в переменнуюcomment.
- В переменной
commentTemplateмы создаем шаблон, и добавляем полученные данные.
- В функции также проверяется условие, является ли комментарий вложенным или нет, и в зависимости от условия выводим в определенном элементе.
Заключительным шагом мы подключим статику в настройках, для этого в settings.py добавим путь для статичных файлов:
STATIC_URL = '/static/'
STATIC_ROOT = (BASE_DIR / 'static')
STATICFILES_DIRS = [BASE_DIR / 'templates/js/']
Теперь давайте запустим сервер и проверим работу комментариев:
Затем нажмём кнопку Добавить комментарий:
Теперь попробуем ответить сами себе:
Мы видим что наши древовидные комментарии прекрасно работают.
В админ панели комментарии будут выглядеть следующим образом:
На этом мы закончим разработку комментариев, в следующем разделе мы добавим теги к нашим записям.