“点击”事件中外部变量的新值在第一次尝试时不会持续存在

问题描述 投票:0回答:1

我正在开发一个待办事项项目,可以单击按钮添加新待办事项,或单击现有卡片来编辑该待办事项。我决定让两者使用相同的形式,但使用不同的“模式”来指示如何处理输入。

如果在页面最初加载后单击卡片然后提交更改,则

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);
  }

预先感谢您的帮助!

javascript addeventlistener variable-assignment
1个回答
0
投票

您可以使用

<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>

© www.soinside.com 2019 - 2024. All rights reserved.