Собственно, у меня есть сгенерированный код js для добавления в форму изображений пользователем и их предпросмотра. Но глобально есть две проблемы.
1) При удалении изображений по кнопке происходит смена индексов (то ли у файлов в input, то ли у кнопок внутри div`a class="image-preview") в связи с этим если удалять начиная с конца к началу по порядку, то всё отлично работает, но если делать с начала в конец или произвольно, то всегда остаётся 1-2 файла в input'е, хотя все изображения из предпросмотра удалены.
пример некорректной работы
Показывает что файла два, а изображение осталось одно.
2) Уже менее критично, но всё же хочу реализовать возможность поочерёдного добавления изображений, а то в текущем состоянии при добавлении новой картинки с помощью input старые файлы автоматически очищаются, а мне это не нужно, ведь для очищения у юзера будут специальные кнопки возле каждого изображения в контейнере предпросмотра. Очевидно нужно убрать очищение сгенерированного innerHtml внутри js функции, но непонятно как сделать так чтобы сохранялись не только картинки в контейнере предпросмотра, но и чтобы фактически файлы внутри input`a тоже сохранялись.
function checkFileCount(input) {
if (input.files.length > 5) {
alert("Вы можете выбрать не более пяти файлов."); //хочу чтобы пользователь не мог загрузить суммарно больше 5 файлов
input.value = ''; // очищаем значение поля input, чтобы пользователь мог выбрать файлы заново
} else {
previewImages(input); //вызываю функцию отвечающую за предпоказ
}
}
function previewImages(input) {
var files = input.files;
var preview = document.querySelector('.image-preview');
//выбираем контейнер где будут отображаться картинки
preview.innerHTML = '';
//очищение этого контейнера от изображений загруженных в предыдущий раз
<b>//эту строку нужно будет закомментировать чтобы реализовать многократное добавление без очищения содержимого input,
// но не всё так просто, проблема в том что закомментировав её старые изображения в предпросмотре будут сохраняться,
// но в input эти старые изображения будут удалены (в пункте 2 говорил про это)</b>
for (var i = 0; i < files.length; i++) { //цикл для чтения изображений
var file = files[i];
var reader = new FileReader();
reader.onload = (function(file, index) {
return function(e) {
var image = document.createElement('img');
//реализуем предпросмотр выбранных изображений
image.src = e.target.result;
image.classList.add('preview-image');
preview.appendChild(image);
var removeButton = document.createElement('button');
//кнопка удаления для каждого изображения
removeButton.textContent = 'X';
removeButton.classList.add('remove-button');
removeButton.onclick = function() {
//добавляем функцию чтобы при нажатии на кнопку удалялись изображения из предпросмотра и из файлов input'a
preview.removeChild(image);
preview.removeChild(removeButton);
// Удаляем файл из выбранных файлов
input.files = removeFile(input.files, index);
};
preview.appendChild(removeButton);
};
})(file, i);
reader.readAsDataURL(file);
}
}
<b>// Функция для удаления файла из списка файлов по индексу.
//В ней как раз таки зарыта собака, потому что после удаления одного из элементов
// индексы других меняются и некоторые дальнейшие удаления происходят некорректно,
// хотя если удалять начиная с конца, то всё работает корректно (в пункте 1 писал об этом)</b>
function removeFile(files, index) {
var newFiles = new DataTransfer();
for (var i = 0; i < files.length; i++) {
if (i !== index) {
newFiles.items.add(files[i]);
}
}
return newFiles.files;
}
<div class="cont">
<label class="filter" for="images">Додати фотографію</label>
<input type="file" id="images" name="images" accept="image/*" onchange="checkFileCount(this)" multiple required>
</div>
Исходный html код
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<link rel="stylesheet" type="text/css" href="css/styles2.css">
<title>Add bus form</title>
</head>
<body>
<header>
<ul class="menu">
<div class="leftPart"><li id="findPet"><a href="/pets">Знайти тварину</a></li>
<li><a href="/rules">Правила адопції</a></li>
<li><a href="/help">Допомогти</a></li>
<li><a href="/aboutProject">Про проєкт</a></li>
</div>
<div class="rightPart"><li id="createAdd"><a href="/myProfile">Додати оголошення</a></li>
<li id="login"><a href="/authorization">Профіль</a></li>
</div>
</ul>
</header>
<div class="center-global-container">
<div class="errorMessage">${errorMessage}</div>
<div class="filters">
<form class="addForm" action="/cats/add" method="post">
</div>
<div class="cont">
<label class="filter" for="images">Додати фотографію</label>
<input type="file" id="images" name="images" accept="image/*" onchange="checkFileCount(this)" multiple required>
</div>
<div class="image-preview"></div>
<button type="submit" name="sumbit" class="sumbit-form">Опублікувати оголошення</button>
</form>
</div>
</div>
</body>
</html>
/*Обнуление*/
*, // Половину стилей пришлось удалить из-за ограничения по объему, но вроде все важные есть
*:before,
*:after{
padding: 0;
margin: 0;
border: 0;
box-sizing: border-box;
}
.image-preview {
display: flex;
}
.image-preview img {
width: 100px;
height: 100px;
object-fit: cover; /* чтобы изображение не растягивалось и не сжималось, сохраняя соотношение сторон */
margin: 5px;
}
.remove-button {
margin-left: -20px;
height: 15px;
width: 15px;
margin-top: 5px;
display: block;
color: red;
}
.remove-button:hover {
cursor: pointer;
background-color: pink;
}
.filters {
background-color: #788AB2;
padding: 10px 20px;
width: 590px;
height: 10%;
box-sizing: border-box;
font-size: 20px;
font-family: Tahoma;
color: white;
display: flex;
flex-direction: column;
}
.filters label, .filters select, .filters option {
flex: 1;
display: inline-block;
margin-bottom: 12px;
line-height: 26px;
}
.filters label {
margin-top: 12px
}
.filters p{
align-self: center;
justify-self: center;
font-size: 24px;
margin-bottom: 10px;
}
.cont {
display: flex;
align-items: center;
justify-content: space-between;
}
.filters select {
position: relative;
display: block;
flex: 3.1;
margin: 5px 0;
font-family: 'Open Sans', 'Helvetica Neue', 'Segoe UI', 'Calibri', 'Arial', sans-serif;
font-size: 18px;
color: #60666d;
flex-basis: 50px;
}
.center-global-container{
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
}
.addForm-container {
width: 32.5%;
min-width: 325px;
display: flex;
flex-direction: column;
}
.addForm {
width: 100%;
display: flex;
flex-direction: column;
}
.errorMessage{
margin-top: 0px;
margin-bottom: 10px;
font-size: 1.25rem;
color: red;
}