Почему у меня картинка не отображаеться в елементах?
Картинку отправляю на сервер, а там она undefined, но на cloudinary загрузилась url и есть картинка. HTML
<!DOCTYPE html>
<html lang="en">
<head>
<!--Для кнопок шрифт-->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Kablammo&display=swap" rel="stylesheet">
<!--Для кнопок шрифт-->
<!--Шрифт для іншого тексту-->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Rubik+Gemstones&display=swap" rel="stylesheet">
<!--Шрифт для іншого тексту-->
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<!--CSS-->
<link rel="stylesheet" href="bg.css">
<link rel="stylesheet" href="buttons.css">
<link rel="stylesheet" href="menu.css">
<link rel="stylesheet" href="modal.css">
<link rel="stylesheet" href="workmenu.css">
<link rel="stylesheet" href="item.css">
<!--CSS-->
<title>Мережеві накопичувачі</title>
</head>
<body>
<!--Модальне вікно-->
<form name="productForm" action="/products" method="POST" id="modalform" enctype="multipart/form-data">
<div class="conteinar" id="modalcont">
<div class="head">
<p class="text-h">
Create NAS
</p>
<div class="btn-grid">
<input type="submit" value="X" id="btn-close" onclick="event.preventDefault(); Modaleclose()">
</div>
</div>
<div class="center">
<input type="hidden" name="productId" id="productId">
<input type="hidden" name="oldCloudinaryPublicId" id="oldCloudinaryPublicId">
<input type="hidden" name="oldImagePath" id="oldImagePath">
<p class="text-p">
Модель NAS:
</p>
<input class="text-field" id="js-input-model" maxlength="30" name="productName" placeholder="Введіть модель NAS" type="text">
<p class="text-p">
Модель процесора:
</p>
<input class="text-field" id="js-proc" maxlength="30" name="productProc" placeholder="Введіть модель процесора" type="text">
<p class="text-p">
Оперативна пам'ять:
</p>
<input class="text-field" id="js-op" min="1" max="9999" onkeypress="return isNumeric(event)" oninput="maxLengthCheck(this)" name="productOp" placeholder="Введіть оперативну пам'ять в ГБ" type="number">
<p class="text-p">
Ціна:
</p>
<input class="text-field" id="js-lan" min="1" max="99999" onkeypress="return isNumeric(event)" oninput="maxLengthCheck(this)" name="productLan" placeholder="Введіть ціну" type="number">
<p class="text-p">
Слоти для дисків:
</p>
<select name="productDisk" id="js-disk" class="select-t">
<option class="text-field" value="1">1</option>
<option class="text-field" value="2">2</option>
<option class="text-field" value="3">3</option>
<option class="text-field" value="4">4</option>
</select>
<p class="text-p" style="padding-bottom: 10px;">
Виберіть файл зображення:
</p>
<input class="file" name="productImage" type="file" id="productImage" accept=".jpeg, .jpg, .png">
<button type="submit" id="submitBtn" onclick="modalpush(); event.preventDefault();" value="Confirm" class="buttonedit">Confirm</button>
</div>
</div>
</form>
<div class="grey" onclick="Modaleclose();" id="greybg"></div>
<!--Модальне вікно-->
<!--menu-->
<div class="menu">
<div class="nameshop">
<b>NAS SHOP</b>
</div>
<div class="search"><input type="search" class="searchfield" placeholder="Search your NAS"/></div>
<div class="green"><button class="green-button">Search</button></div>
</div>
<!--workmenu-->
<div class="workmenu">
<div class="Manage-nas"><b>Manage NAS</b></div>
<div>
<button type="submit" class="create-button" onclick="Modaleshow()">Create</button>
</div>
<div class="switch-elements">
<div class="sort-text">
<b>Sort by price</b>
</div>
<div>
<div class="switch-div">
<label class="switch">
<input type="checkbox" id="sortcheckbox">
<span class="slider round"></span>
</label>
</div>
</div>
</div>
</div>
<!--product-->
<div class="dataContainer">
</div>
<!--JS-->
<script src="buttons.js"></script>
<script src="valid.js"></script>
<script src="forminput.js"></script>
<!--JS-->
</body>
</html>
JS отправка данных с формы и создание елемента
let products = []; // Глобальний масив для зберігання продуктів
function getAndShowAllProducts() {
let sortedProducts = [...products]; // Копіюємо продукти для сортування
//alert(products[0].productImage)
// Сортування за ціною, якщо чекбокс вибраний
const sortCheckbox = document.getElementById("sortcheckbox");
if (sortCheckbox.checked) {
sortedProducts.sort((a, b) => a.productLan - b.productLan);
}
const dataContainer = document.querySelector(".dataContainer");
dataContainer.innerHTML = "";
sortedProducts.forEach((product) => {
let productCard = document.createElement("div");
productCard.classList.add("element");
productCard.innerHTML = `
<div class="element-data">
<img src="${product.productImage}" class="element-img">
<div class="element-name">${product.productName}</div>
<p class="element-text">Процесор: <span class="element-volume">${product.productProc}</span></p>
<p class="element-text">Кількість слотів для дисків: <span class="element-material">${product.productDisk}</span></p>
<p class="element-text">Кількість оперативної пам'яті: <span class="element-material">${product.productOp}</span></p>
<p class="element-text">Ціна: <span class="element-material">${product.productLan}</span></p>
</div>
<div class="element-footer">
<button class="edit-button" onclick="modifyModalToEdit('${product._id}', '${product.productName}', '${product.productProc}', '${product.productDisk}', '${product.productOp}', '${product.productLan}', '${product.productImage}', '${product.cloudinaryPublicId}')">Edit</button><span> </span>
<button class="delete-button" onclick="removeProduct('${product._id}', '${product.cloudinaryPublicId}')">Delete</button>
</div>
`;
dataContainer.appendChild(productCard);
});
}
// Отримання продуктів з бази даних
async function fetchProductsFromDatabase() {
await fetch("/products")
.then(res => res.json())
.then(data => {
products = data
getAndShowAllProducts();
});
}
// Обробник події натискання на кнопку сортування
function handleSortCheckboxChange() {
getAndShowAllProducts(); // Відображаємо продукти з оновленим сортуванням
}
// Додавання слухача подій на зміну стану чекбокса
const sortCheckbox = document.getElementById("sortcheckbox");
sortCheckbox.addEventListener("change", handleSortCheckboxChange);
// Виклик функції fetchProductsFromDatabase() для отримання продуктів з бази даних
fetchProductsFromDatabase();
function collectFormData() {
const productForm = document.forms["productForm"];
let formData = new FormData(productForm);
productForm.reset();
return formData;
}
async function sendData() {
await fetch('/products', {
method: 'POST',
body: collectFormData()
});
}
async function modalpush() {
if (valid() && validImg()) {
await sendData();
fetchProductsFromDatabase(); // Отримати та відобразити оновлений список продуктів
Modaleclose();
}
}
async function removeProduct(_id, cloudinaryPublicId) {
const deleteParams = {
_id: _id,
cloudinaryPublicId: cloudinaryPublicId,
};
await fetch(`/products/${_id}`, {
method: "DELETE",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(deleteParams),
});
fetchProductsFromDatabase();
}
function modifyModalToEdit(_id, productName, productProc, productDisk, productOp, productLan, productImage, cloudinaryPublicId) {
document.getElementById("modalcont").style.display = "block";
document.getElementById("greybg").style.display = "block";
document.getElementsByClassName("text-h")[0].innerText = "Edit NAS";
document.getElementById("submit-btn").innerText = "Update";
document.getElementById('formImage').setAttribute("src", productImage);
document.getElementById("js-input-model-edit").value = productName;
document.getElementById("js-proc-edit").value = productProc;
document.getElementById("js-disk-edit").value = productDisk;
document.getElementById("js-op-edit").value = productOp;
document.getElementById("js-lan-edit").value = productLan;
document.getElementById("productId").value = _id;
document.getElementById('oldImagePath').value = productImage;
document.getElementById("oldCloudinaryPublicId").value = cloudinaryPublicId;
}
// Виклик функції getAndShowAllProducts() після її оголошення
getAndShowAllProducts();
// Обробник події натискання на кнопку пошуку
const searchButton = document.querySelector(".green-button");
searchButton.addEventListener("click", handleSearch);
function handleSearch() {
const searchField = document.querySelector(".searchfield");
const searchTerm = searchField.value.trim().toLowerCase();
if (searchTerm === "") {
// Якщо поле пошуку порожнє, відображаємо всі продукти
getAndShowAllProducts();
return;
}
const filteredProducts = products.filter((product) =>
product.productName.toLowerCase().includes(searchTerm)
);
if (filteredProducts.length > 0) {
// Якщо є знайдені продукти, відображаємо їх
const dataContainer = document.querySelector(".dataContainer");
dataContainer.innerHTML = "";
filteredProducts.forEach((product) => {
let productCard = document.createElement("div");
productCard.classList.add("element");
productCard.innerHTML = `
<div class="element-data">
<img src="${product.productImage}" class="element-img">
<div class="element-name">${product.productName}</div>
<p class="element-text">Процесор: <span class="element-volume">${product.productProc}</span></p>
<p class="element-text">Кількість слотів для дисків: <span class="element-material">${product.productDisk}</span></p>
<p class="element-text">Кількість оперативної пам'яті: <span class="element-material">${product.productOp}</span></p>
<p class="element-text">Ціна: <span class="element-material">${product.productLan}</span></p>
</div>
<div class="element-footer">
<button class="edit-button" onclick="modifyModalToEdit('${product._id}', '${product.productName}', '${product.productProc}', '${product.productDisk}', '${product.productOp}', '${product.productLan}', '${product.productImage}', '${product.cloudinaryPublicId}')">Edit</button><span> </span>
<button class="delete-button" onclick="removeProduct('${product._id}', '${product.cloudinaryPublicId}')">Delete</button>
</div>
`;
dataContainer.appendChild(productCard);
});
} else {
// Якщо немає знайдених продуктів, відображаємо повідомлення
const dataContainer = document.querySelector(".dataContainer");
dataContainer.innerHTML = "<p>No products found.</p>";
}
}
Backend на node.js Express
const express = require('express');
const mongoose = require('mongoose');
const router = express.Router();
const Product = require('./back/modelschema');
const bodyParser = require("body-parser");
const cloudinary = require('cloudinary');
const formidable = require('formidable');
const app = express();
const PORT = 3000;
cloudinary.v2.config({
cloud_name: 'SECRET',
api_key: 'SECRET',
api_secret: 'SECRET',
secure: true,
});
const mongoDB = "SECRET";
mongoose.connect(mongoDB, { useNewUrlParser: true, useUnifiedTopology: true })
.then(() => {
console.log("З'єднання з БД встановлено");
})
.catch((err) => {
console.log(err);
});
app.use(express.static(__dirname + '/public'));
app.listen(PORT, (error) => {
error ? console.log(error) : console.log(`Сервер запущено на порту ${PORT}`);
});
// Отримання всіх продуктів
app.get("/products", (req, res) => {
Product.find({})
.then((products) => {
return res.send(products);
})
.catch((error) => {
console.log(error);
res.status(500).send("Помилка при отриманні продуктів");
});
});
// Видалення продукту
app.delete("/products/:id", (req, res) => {
const productId = req.params.id;
Product.findByIdAndRemove(productId)
.then((product) => {
if (!product) {
return res.status(404).send("Продукт не знайдено");
}
// Видалення зображення з Cloudinary
cloudinary.uploader.destroy(product.cloudinaryPublicId, { invalidate: true }, (error, result) => {
if (error) {
console.log(error);
}
});
res.send("Продукт успішно видалено");
})
.catch((error) => {
console.log(error);
res.status(500).send("Помилка при видаленні продукту");
});
});
router.post("/", (req, res) => {
const form = formidable({
multiples: true,
keepExtensions: true,
});
form.parse(req, async (err, fields, files) => {
if (err) {
console.log("Error parsing the files");
return res.status(400).json({
status: "Fail",
message: "There was an error parsing the files",
error: err,
});
}
const { productId, productName, productProc, productDisk, productOp, productLan, oldCloudinaryPublicId, oldImagePath } = fields;
const { productImage } = files;
const productInfo = {
productName,
productProc,
productDisk,
productOp,
productLan
};
console.log(fields, files)
if (!productImage || !productImage.originalFilename) {
// Якщо зображення не завантажено або не змінено - додаємо старі поля
productInfo.productImage = oldImagePath;
productInfo.cloudinaryPublicId = oldCloudinaryPublicId;
console.log(productInfo.productImage);
saveDataToDB(productId, productInfo, res);
} else {
// Якщо зображення змінено - завантажуємо нове зображення до Cloudinary
const getImagePath = productImage.filepath;
cloudinary.uploader.upload(getImagePath, (err, image) => {
if (err) {
console.warn(err);
}
productInfo.productImage = image && image.url; // Перевірка, чи існує image і має властивість url
productInfo.cloudinaryPublicId = image && image.public_id;
saveDataToDB(productId, productInfo, res);
cloudinary.uploader.destroy(oldCloudinaryPublicId);
});
}
});
});
router.get("/list", (req, res) => {
Product.find((err, docs) => {
if (!err) {
res.send(docs);
} else {
console.warn('Error in retrieving product list:', err);
}
});
});
const jsonParser = express.json();
router.delete("/:id", jsonParser, (req, res) => {
const productId = req.params.id;
cloudinary.uploader.destroy(req.body.cloudinaryPublicId);
Product.findByIdAndDelete(productId, (err, docs) => {
if (err) {
console.log(err);
} else {
res.sendStatus(200);
}
});
});
function saveDataToDB(productId, data, res) {
// Перевіряємо чи створювати новий запис в БД, чи оновлювати наявний
if (productId == "") {
// Створюємо новий запис БД
Product.create(data)
.then(() => {
res.sendStatus(200);
})
.catch((error) => {
console.log(error);
res.status(500).send("Помилка при збереженні продукту");
});
} else {
// Оновлюємо наявний запис БД
Product.findByIdAndUpdate(productId, data)
.then(() => {
res.sendStatus(200);
})
.catch((error) => {
console.log(error);
res.status(500).send("Помилка при оновленні продукту");
});
}
}
app.use("/products", router);
module.exports = router;