我正在开发一个待办事项项目,可以单击按钮添加新待办事项,或单击现有卡片来编辑该待办事项。我决定让两者使用相同的形式,但使用不同的“模式”来指示如何处理输入。
如果在页面最初加载后单击卡片然后提交更改,则
openEditForm
函数将运行并更改外部变量 formMode
和 currentTodo
的值,但当函数完成时,这些变量将恢复为未定义。如果我取消退出表单而不是提交,然后单击另一张卡并尝试提交对该卡的更改,只要我自初始页面加载以来没有提交过一次表单,问题仍然存在。
函数和外部变量在任何其他场景下都可以正常工作(添加新任务、在提交表单后单击卡片至少一次,无论是新任务还是对现有卡片的编辑失败)。
我认为添加新任务(始终正常工作)和编辑现有卡片之间的主要区别在于 openNewForm 不需要任何参数,而 openEditForm 需要参数来识别正在编辑哪个待办事项。我怀疑这意味着当我将这些函数添加到相关的“点击”事件时,问题与范围界定有关,但我已经尝试过
() => openEditForm(project, i)
和当前版本openEditForm.bind(window, project, i)
,并且想不出重写的方法不带参数的函数。
有什么线索吗?完整的代码位于 在 Github 上,但我认为最相关的代码是来自
index.js
:
function ScreenController () {
const todoForm = document.forms["new-todo-form"];
const submitBtn = document.querySelector(".submit-btn");
const contentDiv = document.querySelector(".content");
let formMode = "";
let currentTodo = "";
// load existing to-dos
const updateTodos = function (project) {
contentDiv.innerHTML = "";
const todos = project.todos;
todos.forEach(function (todo, i) {
const card = document.createElement("div");
card.classList.add("todo-card");
card.addEventListener("click", openEditForm.bind(window, project, i));
[...]
}
[...]
const openEditForm = function (project, index) {
// BUGS - CURRENTTODO AND FORMMODE DON'T PERSIST IF CARD IS CLICKED AT BEGINNING, passing function into addeventlistener with parameters
console.log("Open edit form");
console.log({project, index});
currentTodo = project.todos[index];
todoForm.title.value = currentTodo.title;
todoForm.description.value = currentTodo.description;
todoForm.dueDate.value = currentTodo.getDueDate();
todoForm.priority.value = currentTodo.priority;
submitBtn.innerText = "Save task";
formMode = "edit";
console.log(formMode);
toggleForm();
}
[...]
// Submit form depending if it is a new or existing to-do
const submitForm = function () {
todoForm.reportValidity();
console.log(formMode);
switch (formMode) {
case "add":
submitTodo();
break;
case "edit":
editTodo(currentTodo);
break;
}
toggleForm();
updateTodos(defaultProject);
}
[...]
// Edit existing to-do
const editTodo = function(todo) {
let title = todoForm.title.value;
let description = todoForm.description.value;
let dueDate = todoForm.dueDate.value;
let priority = todoForm.priority.value;
defaultProject.updateTodo(todo, title, description, dueDate, priority);
}
预先感谢您的帮助!
<fieldset>
元素来控制显示/启用表单的哪一部分。在这个例子中,我有一个“编辑”和一个“新”字段集。如果单击 + New to-do
,将启用“新”字段集。
如果禁用字段集,则该字段集中的任何表单字段都不会包含在提交事件中。您可以看到“编辑”字段集有一个仅与编辑相关的输入隐藏 ID。
这里的优点是它不需要任何全局变量——形式在任何时候都是“不言自明的”(例如,如果
data.has('id')
为 true,那么它一定是一个编辑)。
document.forms.todo_form.add_btn.addEventListener('click', e => {
let form = e.currentTarget.form;
form.common.disabled = false;
form.edit.disabled = true;
form.new.disabled = false;
});
document.forms.todo_form.addEventListener('click', e => {
switch(e.target.name){
case 'cancel_btn':
let form = e.target.form;
form.reset();
form.common.disabled = true;
form.edit.disabled = true;
form.new.disabled = true;
break;
}
});
document.forms.todo_form.addEventListener('submit', e => {
e.preventDefault();
let form = e.target;
let data = new FormData(form);
if(data.has('id')) console.log('must be an edit');
console.log(Object.fromEntries(data));
});
fieldset {
border: none;
}
fieldset:disabled {
display: none;
}
<div class="content"></div>
<form id="todo_form">
<button class="add-btn" name="add_btn" type="button">+<span> New to-do</span></button>
<fieldset name="common" disabled>
<label for="title">Title<span class="required">*</span></label>
<input id="title" type="text" name="title" placeholder=" " required aria-describedby="required-description">
<label for="description">Description</label>
<textarea id="description" name="description" placeholder=" " rows="4"></textarea>
<label for="due-date">Due</label>
<input id="due-date" type="date" name="dueDate">
<label for="priority">Priority</label>
<select id="priority" name="priority">
<option value="">Please select an option</option>
<option value="high">High</option>
<option value="high">Medium</option>
<option value="high">Low</option>
</select>
</fieldset>
<fieldset name="edit" disabled>
<input type="hidden" name="id">
<button class="submit-btn" type="submit">Save</button>
<button name="cancel_btn" type="button">Cancel</button>
</fieldset>
<fieldset name="new" disabled>
<button class="submit-btn" type="submit">Create</button>
<button name="cancel_btn" type="button">Cancel</button>
</fieldset>
<p aria-hidden="true" id="required-description">
<span class="required">*</span>Required field
</p>
</form>