Работает добавление и удаление фильмов в админке
This commit is contained in:
parent
f75924a03c
commit
52f9769b41
@ -77,7 +77,7 @@
|
||||
</header>
|
||||
<main class="flex-fill d-flex flex-column px-1 px-md-2">
|
||||
<div class="control-group py-2">
|
||||
<button id="items-add" class="btn btn-light">
|
||||
<button id="movie-button-add" class="btn btn-light">
|
||||
Добавить фильм (диалог)
|
||||
</button>
|
||||
</div>
|
||||
@ -150,7 +150,7 @@
|
||||
<img
|
||||
id="image-preview"
|
||||
src="https://via.placeholder.com/160x230"
|
||||
class="rounded-2"
|
||||
class="rounded-2 img-fluid"
|
||||
alt="placeholder"
|
||||
/>
|
||||
</div>
|
||||
|
@ -1,16 +1,151 @@
|
||||
import { ApiEndpoint } from "./apiendpoint";
|
||||
import { ApiEndpoint, createMovieObject } from "./apiendpoint";
|
||||
import { Modal } from "bootstrap";
|
||||
import { modalControls } from "./modalui";
|
||||
|
||||
const moviesApiEndpoint = new ApiEndpoint("movies");
|
||||
const categoriesApiEndpoint = new ApiEndpoint("categories");
|
||||
|
||||
document.addEventListener("DOMContentLoaded", loadMoviesTableData());
|
||||
|
||||
document
|
||||
.getElementById("movie-button-add")
|
||||
.addEventListener("click", buttonMovieAddClicked);
|
||||
|
||||
const modal = document.getElementById("modal-movie");
|
||||
const myModal = modal ? new Modal(modal, {}) : null;
|
||||
|
||||
// myModal.show();
|
||||
|
||||
function createItemsOption(name, value = "", isSelected = false) {
|
||||
const option = document.createElement("option");
|
||||
option.value = value || "";
|
||||
option.selected = isSelected;
|
||||
option.text = name;
|
||||
return option;
|
||||
}
|
||||
|
||||
async function readFile(file) {
|
||||
const reader = new FileReader();
|
||||
|
||||
// создание Promise-объекта для использования функции
|
||||
// с помощью await (асинхронно) без коллбэков (callback)
|
||||
// https://learn.javascript.ru/promise
|
||||
return new Promise((resolve, reject) => {
|
||||
// 2. "Возвращаем" содержимое когда файл прочитан
|
||||
// через вызов resolve
|
||||
// Если не использовать Promise, то всю работу по взаимодействию
|
||||
// с REST API пришлось бы делать в обработчике (callback) функции
|
||||
// onloadend
|
||||
reader.onloadend = () => {
|
||||
const fileContent = reader.result;
|
||||
// Здесь могла бы быть работа с REST API
|
||||
// Чтение заканчивает выполняться здесь
|
||||
resolve(fileContent);
|
||||
};
|
||||
// 3. Возвращаем ошибку
|
||||
reader.onerror = () => {
|
||||
// Или здесь в случае ошибки
|
||||
reject(new Error("oops, something went wrong with the file reader."));
|
||||
};
|
||||
// Шаг 1. Сначала читаем файл
|
||||
// Чтение начинает выполняться здесь
|
||||
reader.readAsDataURL(file);
|
||||
});
|
||||
}
|
||||
|
||||
// TODO
|
||||
// функция для обновления блока с превью выбранного изображения
|
||||
async function updateImagePreview() {
|
||||
// получение выбранного файла
|
||||
// возможен выбор нескольких файлов, поэтому необходимо получить только первый
|
||||
const file = modalControls.inputImage.files[0];
|
||||
// чтение содержимого файла в виде base64 строки
|
||||
const fileContent = await readFile(file);
|
||||
console.info("base64 ", fileContent);
|
||||
// обновление атрибута src для тега img с id image-preview
|
||||
modalControls.imagePreview.src = fileContent;
|
||||
}
|
||||
|
||||
const imagePlaceholder = "./static/images/cover-placeholder160x230.png";
|
||||
|
||||
modalControls.form.addEventListener("submit", async (event) => {
|
||||
// отключение стандартного поведения формы при отправке
|
||||
// при отправке страница обновляется и JS перестает работать
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
// если форма не прошла валидацию, то ничего делать не нужно
|
||||
// if (!cntrls.form.checkValidity()) {
|
||||
// return;
|
||||
// }
|
||||
|
||||
let imageBase64 = "";
|
||||
// Получение выбранного пользователем изображения в виде base64 строки
|
||||
// Если пользователь ничего не выбрал, то не нужно сохранять в БД
|
||||
// дефолтное изображение
|
||||
|
||||
// modalControls.imagePreview.src !== imagePlaceholder
|
||||
// TODO
|
||||
// прописать логиук отображения превью
|
||||
if (modalControls.imagePreview.src !== imagePlaceholder) {
|
||||
// Загрузка содержимого атрибута src тэга img с id image-preview
|
||||
// Здесь выполняется HTTP запрос с типом GET
|
||||
const result = await fetch(modalControls.imagePreview.src);
|
||||
// Получение из HTTP-ответа бинарного содержимого
|
||||
const blob = await result.blob();
|
||||
// Получение base64 строки для файла
|
||||
// Здесь выполняется Promise из функции readFile
|
||||
// Promise позволяет писать линейный код для работы с асинхронными методами
|
||||
// без использования обработчиков (callback) с помощью await
|
||||
imageBase64 = await readFile(blob);
|
||||
}
|
||||
|
||||
// получение id строки для редактирования
|
||||
// это значение содержится в скрытом input
|
||||
const currentId = modalControls.movieId.value;
|
||||
// если значение id не задано,
|
||||
// то необходимо выполнить добавление записи
|
||||
// иначе обновление записи
|
||||
if (!currentId) {
|
||||
const movie = createMovieObject(
|
||||
modalControls.inputName.value,
|
||||
parseInt(modalControls.selectCategory.value),
|
||||
modalControls.inputDuration.value,
|
||||
modalControls.inputDescription.value,
|
||||
imageBase64
|
||||
);
|
||||
await moviesApiEndpoint.createObject(movie);
|
||||
} else {
|
||||
// TODO
|
||||
// await editLine(
|
||||
// currentId,
|
||||
// cntrls.itemsType.value,
|
||||
// cntrls.price.value,
|
||||
// cntrls.count.value,
|
||||
// imageBase64,
|
||||
// );
|
||||
}
|
||||
|
||||
// после выполнения добавления/обновления модальное окно скрывается
|
||||
myModal.hide();
|
||||
await loadMoviesTableData();
|
||||
});
|
||||
|
||||
async function buttonMovieAddClicked(e) {
|
||||
modalControls.title.innerText = "Добавить фильм";
|
||||
modalControls.selectCategory.innerHTML = "";
|
||||
const categories = await categoriesApiEndpoint.getObjects();
|
||||
modalControls.selectCategory.appendChild(
|
||||
createItemsOption("Выберите жанр", "", true)
|
||||
);
|
||||
for (let i = 0; i < categories.length; i++) {
|
||||
const category = categories[i];
|
||||
modalControls.selectCategory.appendChild(
|
||||
createItemsOption(category.name, category.id)
|
||||
);
|
||||
}
|
||||
myModal.show();
|
||||
}
|
||||
|
||||
async function movieDeleteButtonClicked(e) {
|
||||
console.log(e.target);
|
||||
const movieId = parseInt(e.target.id.split("-")[3]);
|
||||
@ -18,12 +153,24 @@ async function movieDeleteButtonClicked(e) {
|
||||
await loadMoviesTableData();
|
||||
}
|
||||
|
||||
async function movieEditButtonClicked(e) {}
|
||||
async function movieEditButtonClicked(e) {
|
||||
// TODO
|
||||
// получить объект по id
|
||||
// заполнение модального окна по данным объекта
|
||||
// показ модального окна
|
||||
}
|
||||
|
||||
async function loadMoviesTableData() {
|
||||
const movies = await moviesApiEndpoint.getObjects();
|
||||
const category = await categoriesApiEndpoint.getObjects();
|
||||
const tableWrapper = document.getElementById("movie-table-body");
|
||||
|
||||
// Вызов функции обновления превью изображения при возникновении
|
||||
// события oncahnge в тэге input с id image
|
||||
modalControls.inputImage.addEventListener("change", () =>
|
||||
updateImagePreview()
|
||||
);
|
||||
|
||||
tableWrapper.innerHTML = "";
|
||||
|
||||
for (let i = 0; i < movies.length; i++) {
|
||||
|
@ -1,89 +1,91 @@
|
||||
const serverUrl = "http://localhost:8081";
|
||||
|
||||
// export function createPostObject(
|
||||
// userId,
|
||||
// createdDateTime,
|
||||
// text,
|
||||
// img,
|
||||
// ) {
|
||||
// return {
|
||||
// userId,
|
||||
// createdDateTime,
|
||||
// text,
|
||||
// img,
|
||||
// };
|
||||
// }
|
||||
export function createMovieObject(
|
||||
name,
|
||||
categoryId,
|
||||
duration,
|
||||
description,
|
||||
img
|
||||
) {
|
||||
return {
|
||||
name,
|
||||
categoryId,
|
||||
duration,
|
||||
description,
|
||||
img,
|
||||
};
|
||||
}
|
||||
|
||||
export class ApiEndpoint {
|
||||
constructor(endpoint) {
|
||||
this.endpoint = endpoint;
|
||||
constructor(endpoint) {
|
||||
this.endpoint = endpoint;
|
||||
}
|
||||
|
||||
async getObjects() {
|
||||
const response = await fetch(`${serverUrl}/${this.endpoint}`);
|
||||
if (!response.ok) {
|
||||
throw response.statusText;
|
||||
}
|
||||
return response.json();
|
||||
}
|
||||
|
||||
async getObjects() {
|
||||
const response = await fetch(`${serverUrl}/${this.endpoint}`);
|
||||
if (!response.ok) {
|
||||
throw response.statusText;
|
||||
}
|
||||
return response.json();
|
||||
async getObject(id) {
|
||||
const response = await fetch(`${serverUrl}/${this.endpoint}/${id}`);
|
||||
if (!response.ok) {
|
||||
throw response.statusText;
|
||||
}
|
||||
return response.json();
|
||||
}
|
||||
|
||||
async getObject(id) {
|
||||
const response = await fetch(`${serverUrl}/${this.endpoint}/${id}`);
|
||||
if (!response.ok) {
|
||||
throw response.statusText;
|
||||
}
|
||||
return response.json();
|
||||
async createObject(obj) {
|
||||
const options = {
|
||||
method: "POST",
|
||||
body: JSON.stringify(obj),
|
||||
headers: {
|
||||
Accept: "application/json",
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
};
|
||||
|
||||
const response = await fetch(`${serverUrl}/${this.endpoint}`, options);
|
||||
if (!response.ok) {
|
||||
throw response.statusText;
|
||||
}
|
||||
return response.json();
|
||||
}
|
||||
|
||||
async createObject(obj) {
|
||||
const options = {
|
||||
method: "POST",
|
||||
body: JSON.stringify(obj),
|
||||
headers: {
|
||||
"Accept": "application/json",
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
};
|
||||
async updateObject(obj) {
|
||||
const options = {
|
||||
method: "PUT",
|
||||
body: JSON.stringify(obj),
|
||||
headers: {
|
||||
Accept: "application/json",
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
};
|
||||
|
||||
const response = await fetch(`${serverUrl}/${this.endpoint}`, options);
|
||||
if (!response.ok) {
|
||||
throw response.statusText;
|
||||
}
|
||||
return response.json();
|
||||
const response = await fetch(
|
||||
`${serverUrl}/${this.endpoint}/${obj.id}`,
|
||||
options
|
||||
);
|
||||
if (!response.ok) {
|
||||
throw response.statusText;
|
||||
}
|
||||
return response.json();
|
||||
}
|
||||
|
||||
async updateObject(obj) {
|
||||
const options = {
|
||||
method: "PUT",
|
||||
body: JSON.stringify(obj),
|
||||
headers: {
|
||||
"Accept": "application/json",
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
};
|
||||
async deleteObject(id) {
|
||||
const options = {
|
||||
method: "DELETE",
|
||||
};
|
||||
|
||||
const response = await fetch(
|
||||
`${serverUrl}/${this.endpoint}/${obj.id}`,
|
||||
options,
|
||||
);
|
||||
if (!response.ok) {
|
||||
throw response.statusText;
|
||||
}
|
||||
return response.json();
|
||||
}
|
||||
|
||||
async deleteObject(id) {
|
||||
const options = {
|
||||
method: "DELETE",
|
||||
};
|
||||
|
||||
const response = await fetch(
|
||||
`${serverUrl}/${this.endpoint}/${id}`,
|
||||
options,
|
||||
);
|
||||
if (!response.ok) {
|
||||
throw response.statusText;
|
||||
}
|
||||
return response.json();
|
||||
const response = await fetch(
|
||||
`${serverUrl}/${this.endpoint}/${id}`,
|
||||
options
|
||||
);
|
||||
if (!response.ok) {
|
||||
throw response.statusText;
|
||||
}
|
||||
return response.json();
|
||||
}
|
||||
}
|
||||
|
13
static/js/modalui.js
Normal file
13
static/js/modalui.js
Normal file
@ -0,0 +1,13 @@
|
||||
const movieModal = document.getElementById("modal-movie");
|
||||
|
||||
export const modalControls = {
|
||||
title: document.getElementById("movie-modal-title"),
|
||||
imagePreview: document.getElementById("image-preview"),
|
||||
selectCategory: document.getElementById("category"),
|
||||
inputName: document.getElementById("name"),
|
||||
inputDuration: document.getElementById("duration"),
|
||||
inputDescription: document.getElementById("description"),
|
||||
inputImage: document.getElementById("image"),
|
||||
form: document.getElementById("movie-form"),
|
||||
movieId: document.getElementById("movie-id"),
|
||||
};
|
Loading…
Reference in New Issue
Block a user