Я довольно новичок в js. Я пытаюсь завершить приложение типа todo. Мне удалось создать, отобразить и удалить элемент массива, но у меня возникли проблемы с редактированием.
Все эти операции выполняются с помощью библиотеки uuidv4 для генерации идентификатора для каждого созданного элемента массива.
С индивидуальным идентификатором, выбранным для элемента массива, я создаю динамические кнопки, одну для удаления элемента массива, другую для редактирования.
После нажатия кнопки «Изменить» я хочу открыть модальное окно, содержащее содержимое выбранного элемента массива. После внесения изменений кнопка редактирования внутри модального окна должна вызвать функцию редактирования, чтобы обновить изменения, а затем повторно отобразить массив.
Моя проблема в том, что я не могу открыть модальное диалоговое окно при нажатии кнопки редактирования.
Это код для создания необходимой структуры, код для создания, рендеринга и удаления не включен, так как они работают правильно.
// Generate the DOM structure for a todo
const generateTodoDOM = function(todo) {
const todoEl = document.createElement("div");
const checkbox = document.createElement("input");
const label = document.createElement("label");
checkbox.appendChild(label);
todoEl.setAttribute("id", "myTodos");
const textEl = document.createElement("p");
const editButton = document.createElement("button");
editButton.setAttribute("id", "modal-btn");
const removeButton = document.createElement("button");
const createDate = document.createElement("p");
createDate.textContent = `Created: ${dateCreated}`;
createDate.style.color = "#956E93";
// Setup the todo text
textEl.textContent = todo.text;
todoEl.appendChild(textEl);
// Setup the remove button
removeButton.textContent = "x";
todoEl.appendChild(removeButton);
removeButton.addEventListener("click", function() {
removeTodo(todo.id);
saveTodos(todos);
renderTodos(todos, filters);
});
// TODO: Setup the edit note button
editButton.textContent = "Edit Todo";
todoEl.appendChild(editButton);
editButton.addEventListener("click", function() {
//Launch the modal
editModal(todo.id);
});
// Setup todo checkbox
checkbox.setAttribute("type", "checkbox");
checkbox.checked = todo.completed;
todoEl.appendChild(checkbox);
checkbox.addEventListener("change", function() {
toggleTodo(todo.id);
saveTodos(todos);
renderTodos(todos, filters);
});
todoEl.appendChild(createDate);
return todoEl;
};
Код модального окна следующий:
//Edit modal todo by id
const editModal = function(id) {
const todoIndex = todos.findIndex(function(todo) {
return todo.id === id;
});
if (todoIndex > -1) {
const modal = document.querySelector("#my-modal");
const modalBtn = document.querySelector("#modal-btn");
const editTodoContentBtn = document.querySelector("#submitEditTodo")
const closeBtn = document.querySelector(".close");
// Events
modalBtn.addEventListener("click", openModal);
closeBtn.addEventListener("click", closeModal);
editTodoContentBtn.addEventListener("click", editTodo)
window.addEventListener("click", outsideClick);
// Open
function openModal() {
modal.style.display = "block";
}
// Close
function closeModal() {
modal.style.display = "none";
}
// Close If Outside Click
function outsideClick(e) {
if (e.target == modal) {
modal.style.display = "none";
}
}
//Edit the content of the textarea
function editTodo(e) {
editTodo(id)
}
}
};
При нажатии кнопки submitEditTodo должна быть запущена следующая функция редактирования:
//Edit todo by id
const editTodo = function(id) {
const editTodoContent = document.querySelector('#editTodo')
const todoIndex = todos.findIndex(function(todo) {
return todo.id === id;
});
if (todoIndex > -1) {
editTodoContent.value = todos.text
saveTodos(todos)
renderTodos(todos, filters);
}
};
SaveTodos и renderTodos правильно работают с другими функциями для создания, рендеринга и удаления.
Это HTML-код:
<!-- Edit modal -->
<div id = "my-modal" class = "modal">
<div class = "modal-content">
<div class = "modal-header">
<span class = "close">×</span>
<h2>Edit Todo</h2>
</div>
<div class = "modal-body">
<textarea name = "" class = "editTextArea" id = "editTodo" rows = "10"></textarea>
<button class = "button" id = "submitEditTodo">Edit Todo</button>
</div>
<div class = "modal-footer">
<!-- <h3>Modal Footer</h3> -->
</div>
</div>
<!-- End modal -->
и это CSS для модального окна:
/*
Edit todo modal start
*/
:root {
--modal-duration: 1s;
--modal-color: #BB8AB8;
}
.modal {
display: none;
position: fixed;
z-index: 1;
left: 0;
top: 0;
height: 100%;
width: 100%;
overflow: auto;
background-color: rgba(0, 0, 0, 0.5);
}
.modal-content {
margin: 10% auto;
width: 35%;
box-shadow: 0 5px 8px 0 rgba(0, 0, 0, 0.2), 0 7px 20px 0 rgba(0, 0, 0, 0.17);
animation-name: modalopen;
animation-duration: var(--modal-duration);
}
.editTextArea{
width:100%
}
.modal-header h2,
.modal-footer h3 {
margin: 0;
}
.modal-header {
background: var(--modal-color);
padding: 15px;
color: #fff;
border-top-left-radius: 5px;
border-top-right-radius: 5px;
}
.modal-body {
padding: 10px 20px;
background: #fff;
}
.modal-footer {
background: var(--modal-color);
padding: 10px;
color: #fff;
text-align: center;
border-bottom-left-radius: 5px;
border-bottom-right-radius: 5px;
}
.close {
color: #ccc;
float: right;
font-size: 30px;
color: #fff;
}
.close:hover,
.close:focus {
color: #000;
text-decoration: none;
cursor: pointer;
}
@keyframes modalopen {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
/*
Edit todo modal end
*/
Спасибо



![Безумие обратных вызовов в javascript [JS]](https://i.imgur.com/WsjO6zJb.png)


Ниже приведены несколько указателей на то, где вам могут понадобиться корректировки для достижения того, что вы хотите.
В настоящее время вы добавляете новых слушателей в модальное окно каждый раз, когда нажимаете кнопку редактирования задачи. Вероятно, это должно быть установлено только один раз. В качестве альтернативы вы должны удалить слушателей, когда модальное окно закрыто.
Ваша функция editModal на самом деле не открывает модальное окно. Что он делает, так это добавляет прослушиватель к кнопке #modal-btn, которая затем откроет модальное окно при следующем нажатии кнопки.
Вы устанавливаете идентификаторы как для внешнего div, так и для кнопки редактирования, но идентификаторы не основаны ни на чем, связанном с создаваемым вами элементом todo. Таким образом, все эти элементы имеют один и тот же идентификатор. Идентификатор (сокращение от идентификатора) обычно должен быть уникальным. Вместо этого для группировки нескольких элементов следует использовать атрибут класса.
Ваша функция "editTodo" вызывает сама себя. Рекурсия на неопределенный срок. Остерегайтесь повторного использования имен функций.
С учетом вышесказанного приведенный ниже код представляет собой грубый способ сделать то, что, как я думаю, вы хотите сделать на основе предоставленных вами фрагментов:
// Open
const openModal = function() {
document.querySelector("#my-modal").style.display = "block";
}
// Close
const closeModal = function() {
document.querySelector("#my-modal").style.display = "none";
}
function initModal() {
const modal = document.querySelector("#my-modal");
const closeBtn = document.querySelector(".close");
// Events
closeBtn.addEventListener("click", closeModal);
window.addEventListener("click", outsideClick);
// Close If Outside Click
function outsideClick(e) {
if (e.target == modal) {
modal.style.display = "none";
}
}
}
const filters = []; // dummy variable
// Generate the DOM structure for a todo
var todos = []
function generateTodoDOM(todo) {
todos.push(todo);
const todoEl = document.createElement("div");
const checkbox = document.createElement("input");
const label = document.createElement("label");
checkbox.appendChild(label);
todoEl.setAttribute("id", "my-todos-" + todo.id);
const textEl = document.createElement("p");
const editButton = document.createElement("button");
editButton.setAttribute("id", "modal-btn-" + todo.id);
const removeButton = document.createElement("button");
const createDate = document.createElement("p");
createDate.textContent = 'Created: ' + new Date();
createDate.style.color = "#956E93";
// Setup the todo text
textEl.textContent = todo.text;
todoEl.appendChild(textEl);
// Setup the remove button
removeButton.textContent = "x";
todoEl.appendChild(removeButton);
removeButton.addEventListener("click", function() {
removeTodo(todo.id);
saveTodos(todos);
renderTodos(todos, filters);
});
// TODO: Setup the edit note button
editButton.textContent = "Edit Todo";
todoEl.appendChild(editButton);
editButton.addEventListener("click", function() {
//Launch the modal
editModal(todo.id);
openModal();
});
// Setup todo checkbox
checkbox.setAttribute("type", "checkbox");
checkbox.checked = todo.completed;
todoEl.appendChild(checkbox);
checkbox.addEventListener("change", function() {
toggleTodo(todo.id);
saveTodos(todos);
renderTodos(todos, filters);
});
todoEl.appendChild(createDate);
return todoEl;
};
var editFn
//Edit modal todo by id
const editModal = function(id) {
const todoIndex = todos.findIndex(function(todo) {
return todo.id === id;
});
if (todoIndex > -1) {
const modal = document.querySelector("#my-modal");
const editElm = document.querySelector("#editTodo");
const editTodoContentBtn = document.querySelector("#submitEditTodo")
editElm.value = todos[todoIndex].text;
// Events
editTodoContentBtn.removeEventListener("click", editFn)
//Edit the content of the textarea
editFn = function(e) {
editTodo(id)
closeModal()
}
editTodoContentBtn.addEventListener("click", editFn)
}
};
//Edit todo by id
const editTodo = function(id) {
const editTodoContent = document.querySelector('#editTodo')
const todoIndex = todos.findIndex(function(todo) {
return todo.id === id;
});
if (todoIndex > -1) {
todos[todoIndex].text = editTodoContent.value;
saveTodos(todos)
renderTodos(todos, filters);
}
};
const saveTodos = function(todos) {
// dummy method, we're keeping it in memory for this example
}
const renderTodos = function(todosToRender) {
todos = []; // clear current in-memory array
var todoList = document.getElementById("todo-container");
while (todoList.firstChild) {
todoList.removeChild(todoList.firstChild);
}
for(var i = 0; i < todosToRender.length; i++) {
todoList.appendChild(generateTodoDOM(todosToRender[i]));
}
};
initModal();
const container = document.getElementById("todo-container");
var generatedTodos = [];
for(var i = 0; i < 10; i++) {
var todo = { text: "Todo " + (i+1), id: "todo-" + i, completed: false};
generatedTodos.push(todo);
}
renderTodos(generatedTodos);/*
Edit todo modal start
*/
:root {
--modal-duration: 1s;
--modal-color: #BB8AB8;
}
.modal {
display: none;
position: fixed;
z-index: 1;
left: 0;
top: 0;
height: 100%;
width: 100%;
overflow: auto;
background-color: rgba(0, 0, 0, 0.5);
}
.modal-content {
margin: 10% auto;
width: 35%;
box-shadow: 0 5px 8px 0 rgba(0, 0, 0, 0.2), 0 7px 20px 0 rgba(0, 0, 0, 0.17);
animation-name: modalopen;
animation-duration: var(--modal-duration);
}
.editTextArea{
width:100%
}
.modal-header h2,
.modal-footer h3 {
margin: 0;
}
.modal-header {
background: var(--modal-color);
padding: 15px;
color: #fff;
border-top-left-radius: 5px;
border-top-right-radius: 5px;
}
.modal-body {
padding: 10px 20px;
background: #fff;
}
.modal-footer {
background: var(--modal-color);
padding: 10px;
color: #fff;
text-align: center;
border-bottom-left-radius: 5px;
border-bottom-right-radius: 5px;
}
.close {
color: #ccc;
float: right;
font-size: 30px;
color: #fff;
}
.close:hover,
.close:focus {
color: #000;
text-decoration: none;
cursor: pointer;
}
@keyframes modalopen {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
/*
Edit todo modal end
*/<!DOCTYPE html>
<html>
<head>
<link rel = "stylesheet" href = "style.css">
</head>
<body>
<div id = "todo-container">
</div>
<!-- Edit modal -->
<div id = "my-modal" class = "modal">
<div class = "modal-content">
<div class = "modal-header">
<span class = "close">×</span>
<h2>Edit Todo</h2>
</div>
<div class = "modal-body">
<textarea name = "" class = "editTextArea" id = "editTodo" rows = "10"></textarea>
<button class = "button" id = "submitEditTodo">Edit Todo</button>
</div>
<div class = "modal-footer">
<!-- <h3>Modal Footer</h3> -->
</div>
</div>
</div>
<!-- End modal -->
</body>
</html>