【问题标题】:Electron's localstorage not saving my on-click events on dynamically created elementsElectron 的本地存储没有将我的点击事件保存在动态创建的元素上
【发布时间】:2019-04-23 17:07:46
【问题描述】:

我正在使用 Electron 创建一个桌面应用程序,但我遇到了关于点击事件的本地存储的问题。

在我的应用程序中,用户输入了 5 组信息(出版物名称、出版商名称、状态、提交日期、响应日期)

然后通过 D.O.M 将信息放入 HTML 表格中,在表格中,信息按条目分为行,按信息类别分为列,最右侧的列上有“删除”和“编辑”按钮。

例如

|name1|publisher1|awaiting|noDate|NoDate2|[RemoveButton][EditButton]|

|name2|publisher2|denied|noDate3|NoDate4|[RemoveButton]|[EditButton]|

|name3|publisher3|accepted|noDate5|NoDate6|[RemoveButton]|[EditButton]|

等等,随着用户输入的条目越多,表格中附加的行就越多。但是,附加的每一行总是在右侧有 2 个删除和编辑按钮。我已经为这两个按钮分配了一个功能,如下所示:

删除按钮:

editButton.addEventListener("click", function() {
 if (confirm("Are you sure you want to delete this item?")) {
         var td = event.target.parentNode;
         var tr = td.parentNode;
         tr.parentNode.removeChild(tr);

         localStorage.setItem("TableStorage", table.innerHTML);
       } else {}
     };

编辑按钮:

 editButton.addEventListener("click", function() {
       if (confirm("Are you sure you want to edit this item?")) {
         var publicationName = document.getElementById("publicationNameTextField");
         var publisherName = document.getElementById("publisherNameTextField");
         var publicationStatus = document.getElementById(
           "publicationStatusTextField"
         );
         var publicationDateSubmitted = document.getElementById(
           "publicationDateSubmittedTextField"
         );
         var publicationDateResponse = document.getElementById(
           "publicationDateResponseTextField"
         );
         var table = document.getElementById("myTable");
         var td = event.target.parentNode;
         var tr = td.parentNode;

     rowIndex = tr.rowIndex;

     var cell1 = table.rows[rowIndex].cells[0].innerHTML;
     var cell2 = table.rows[rowIndex].cells[1].innerHTML;
     var cell3 = table.rows[rowIndex].cells[2].innerHTML;
     var cell4 = table.rows[rowIndex].cells[3].innerHTML;
     var cell5 = table.rows[rowIndex].cells[4].innerHTML;

     publicationName.value = cell1;
     publisherName.value = cell2;
     publicationStatus.value = cell3;
     publicationDateSubmitted.value = cell4;
     publicationDateResponse.value = cell5;
     publicationName.focus();
     localStorage.setItem("TableStorage", table.innerHTML);
     tr.parentNode.removeChild(tr);
   } else {}
 };

(进一步详细说明编辑按钮,它删除了按钮所在的行,并将所有列条目发布名称、状态等重新输入到要修改和重新提交的文本字段中。)

(代码的格式可能不准确,因为我不习惯在这里格式化)

这些按钮在活动会话期间发挥作用(当应用程序运行时添加提交时),但是当我关闭应用程序并重新打开它和/或强制重新加载它时,这些按钮似乎失去了它们的功能。我认为这是我如何存储本地存储的某种问题。

我确实觉得奇怪的是,我有一个“清除所有按钮”,它基本上清除了表格中的所有内容。此按钮的格式与其他按钮的格式相同,但它不像它们那样动态生成。因此,它让我相信我的函数的声明方式存在问题。

var clearBtn = document.getElementById("clearAllButton");
clearBtn.addEventListener("click", function() {
  if (confirm("Are you sure you want to clear your Publications?")) {
    for (var i = 1; i < table.rows.length; ) {
      table.deleteRow(i);

      localStorage.setItem("TableStorage", table.innerHTML);
    }
  } else {
  }
});

这里是完整的sn-p代码:

   // ALL javascript code that interacts with the page is used here.

// This code is required in the HTML by a require('renderer.js) and thus runs from the page.

// The DOM can be accessed from this file.

// Declare variables from document
//var publicationName = document.getElementById('publicationNameTextField');
//var publisherName = document.getElementById('publisherNameTextField');
//var publicationStatus = document.getElementById('publicationStatusTextField');
//var publicationDateSubmitted = document.getElementById('publicationDateSubmittedTextField');
//var publicationDateResponse = document.getElementById('publicationDateResponseTextField');
"use strict";

// Save Data on close
window.onclose = function() {
  localStorage.setItem("TableStorage", table.innerHTML);
};

// Save data failsafe in event of crash
window.onabort = function() {
  localStorage.setItem("TableStorage", table.innerHTML);
};

// Declare submit button
var submitBtn = document.getElementById("submitButton");

// Declare table data will be displayed and saved to
var table = document.getElementById("myTable");

// Get value of textfields from DOM
var publicationName = document.getElementById("publicationNameTextField").value;
var publisherName = document.getElementById("publisherNameTextField").value;
var publicationStatus = document.getElementById("publicationStatusTextField")
  .value;
var publicationDateSubmitted = document.getElementById(
  "publicationDateSubmittedTextField"
).value;
var publicationDateResponse = document.getElementById(
  "publicationDateResponseTextField"
).value;

// Create a event listener for when the add button is pressed.
submitBtn.addEventListener("click", function(o) {
  // Re declare variables for scope
  var table = document.getElementById("myTable");

  var publicationName = document.getElementById("publicationNameTextField")
    .value;
  var publisherName = document.getElementById("publisherNameTextField").value;
  var publicationStatus = document.getElementById("publicationStatusTextField")
    .value;
  var publicationDateSubmitted = document.getElementById(
    "publicationDateSubmittedTextField"
  ).value;
  var publicationDateResponse = document.getElementById(
    "publicationDateResponseTextField"
  ).value;

  // Save values entered as possible option entries for later submissions.
  var publicationNameDataList = document.getElementById(
    "publicationNameDataList"
  );
  var publicationNameOption = document.createElement("option");
  publicationNameOption.innerHTML = publicationName;
  publicationNameDataList.appendChild(publicationNameOption);

  var publisherNameDataList = document.getElementById("publisherNameDataList");
  var publisherNameOption = document.createElement("option");
  publisherNameOption.innerHTML = publisherName;
  publisherNameDataList.appendChild(publisherNameOption);

  var publicationDateSubmittedDataList = document.getElementById(
    "publicationDateSubmittedDataList"
  );
  var publicationDateSubmittedOption = document.createElement("option");
  publicationDateSubmittedOption.innerHTML = publicationDateSubmitted;
  publicationDateSubmittedDataList.appendChild(publicationDateSubmittedOption);

  var publicationDateResponseDataList = document.getElementById(
    "publicationDateResponseDataList"
  );
  var publicationDateResponseOption = document.createElement("option");
  publicationDateResponseOption.innerHTML = publicationDateResponse;
  publicationDateResponseDataList.appendChild(publicationDateResponseOption);

  // Add a button to remove the particular row on each row
  var deleteButton = document.createElement("img");
  deleteButton.className = "deleteButton";
  deleteButton.innerHTML = "Remove";
  deleteButton.addEventListener("click", function() {
    if (confirm("Are you sure you want to delete this item?")) {
     var td = event.target.parentNode;
     var tr = td.parentNode;
     tr.parentNode.removeChild(tr);

     localStorage.setItem("TableStorage", table.innerHTML);
   } else {}
  });
  deleteButton.src = "assets/img/icons8-cancel-48.png";

  var editButton = document.createElement("img");
  editButton.className = "editButton";
  editButton.innerHTML = "Edit";
  editButton.addEventListener("click", function() {
   if (confirm("Are you sure you want to edit this item?")) {
     var publicationName = document.getElementById("publicationNameTextField");
     var publisherName = document.getElementById("publisherNameTextField");
     var publicationStatus = document.getElementById(
       "publicationStatusTextField"
     );
     var publicationDateSubmitted = document.getElementById(
       "publicationDateSubmittedTextField"
     );
     var publicationDateResponse = document.getElementById(
       "publicationDateResponseTextField"
     );
     var table = document.getElementById("myTable");
     var td = event.target.parentNode;
     var tr = td.parentNode;

     rowIndex = tr.rowIndex;

     var cell1 = table.rows[rowIndex].cells[0].innerHTML;
     var cell2 = table.rows[rowIndex].cells[1].innerHTML;
     var cell3 = table.rows[rowIndex].cells[2].innerHTML;
     var cell4 = table.rows[rowIndex].cells[3].innerHTML;
     var cell5 = table.rows[rowIndex].cells[4].innerHTML;

     publicationName.value = cell1;
     publisherName.value = cell2;
     publicationStatus.value = cell3;
     publicationDateSubmitted.value = cell4;
     publicationDateResponse.value = cell5;
     publicationName.focus();
     localStorage.setItem("TableStorage", table.innerHTML);
     tr.parentNode.removeChild(tr);
   } else {}
  });
  editButton.src = "assets/img/icons8-edit-file-40.png";

  // Create cells for each row
  var row = table.insertRow(1);
  var cell1 = row.insertCell(0);
  var cell2 = row.insertCell(1);
  var cell3 = row.insertCell(2);
  var cell4 = row.insertCell(3);
  var cell5 = row.insertCell(4);
  var cell6 = row.insertCell(5);
  var cell7 = row.insertCell(6);

  // Give each cell of the row content from the textfields
  cell1.innerHTML = publicationName;
  cell2.innerHTML = publisherName;
  cell3.innerHTML = publicationStatus;
  cell4.innerHTML = publicationDateSubmitted;
  cell5.innerHTML = publicationDateResponse;
  cell6.appendChild(deleteButton);
  cell7.appendChild(editButton);

  // Save data to localstorage
  localStorage.setItem("TableStorage", table.innerHTML);

  // Clear text fields for next entry
  document.getElementById("publicationNameTextField").value = "";
  document.getElementById("publisherNameTextField").value = "";
  document.getElementById("publicationStatusTextField").value = "";
  document.getElementById("publicationDateSubmittedTextField").value = "";
  document.getElementById("publicationDateResponseTextField").value = "";
});
// Load previous data upon application loading
window.onload = function() {
  var saved = localStorage.getItem("TableStorage");

  // If there are any saved items, update our list
  if (saved) {
    table.innerHTML = saved;
  }
};
// Clear Button to clear all items of the table.
var clearBtn = document.getElementById("clearAllButton");
clearBtn.addEventListener("click", function() {
  if (confirm("Are you sure you want to clear your Publications?")) {
    for (var i = 1; i < table.rows.length; ) {
      table.deleteRow(i);

      localStorage.setItem("TableStorage", table.innerHTML);
    }
  } else {
  }
});
body {
    font-family: Arial, Helvetica, sans-serif;
}

* {
    box-sizing: border-box;
}


#form {
    text-align: center;
}

.input-container {
    display: -ms-flexbox;
    /* IE10 */
    display: flex;
    width: 100%;
    margin-bottom: 15px;
    text-align: left;
}

.blueB {
    padding: 10px;
    background: dodgerblue;
    color: white;
    min-width: 50px;
    text-align: center;
}

.input-field {
    width: 100%;
    padding: 10px;
    outline: none;
}

.input-field:focus {
    border: 2px solid dodgerblue;
}

/* Set a style for the submit button */
.btn {
    background-color: dodgerblue;
    color: white;
    padding: 15px 20px;
    border: none;
    cursor: pointer;
    width: 50%;
    opacity: 0.9;
}

.btn:hover {
    opacity: 1;
}







img:hover {
    transform: scale(1.1);
    cursor: pointer;
}

/* Style the main content */
.main {
    /* Same as the width of the sidenav */
    padding: 0px 10px;
}

/* Add media queries for small screens (when the height of the screen is less than 450px, add a smaller padding and font-size) */
@media screen and (max-height: 450px) {
    .sidebar {
        padding-top: 15px;
    }

    .sidebar a {
        font-size: 18px;
    }
}


p {
    color: white;
}

h1 {
    color: #3500D3;
}

h2 {
    color: white;

}

#myInput {
    background-image: url('../assets/img/icons8-search-32.png');
    /* Add a search icon to input */
    background-position: 10px 10px;
    /* Position the search icon */
    background-repeat: no-repeat;
    /* Do not repeat the icon image */
    width: 100%;
    /* Full-width */
    font-size: 16px;
    /* Increase font-size */
    padding: 12px 20px 12px 40px;
    /* Add some padding */
    border: 1px solid #3500D3;
    /* Add a grey border */
    margin-bottom: 12px;
    /* Add some space below the input */
}


.PublicationShow {
    height: 50%;
    width: 100%;
    overflow: auto;

}

#myTable {
    border-collapse: collapse;
    /* Collapse borders */
    width: 100%;
    /* Full-width */
    border: 1px solid #3500D3;
    /* Add a grey border */
    font-size: 18px;
    height: 50%;
    overflow-y: auto;
    /* Increase font-size */
    text-align: center;
}

#myTable th,
#myTable td {
    text-align: center;
    /* Left-align text */
    padding: 12px;
    /* Add padding */
}

#myTable tr {
    /* Add a bottom border to all table rows */
    border-bottom: 1px solid #ddd;
}

#myTable tr.header,
#myTable tr:hover {
    /* Add a grey background color to the table header and on hover */
    background-color: #3500D3;
}

td {
    color: white;
}

#clearItemText {
    display: inline;
    text-align: center;
    top: 50%;
}

.deleteButton {
    border-radius: 50%;

}



.editButton {
    border-radius: 50%;

}


.trashHover {
    background-color: none !important;
    color: white;
    font-size: 35px;
}

.trashHover:hover {
    transform: scale(1.1);
    cursor: pointer;
    color: #fb0253;

}
<!DOCTYPE html>
<html style="width: 100%; height: 90%; background-color: #190061">

<head>
  <meta charset="UTF-8" />
  <title>Easy Track | Publication Manager</title>
  <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm"
    crossorigin="anonymous" />
  <link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.5.0/css/all.css" integrity="sha384-B4dIYHKNBt8Bc12p+WXckhzcICo0wtJAoU8YZTY5qE0Id1GSseTk6S+L3BlXeVIU"
    crossorigin="anonymous" />
  <link rel="stylesheet" href="css/index.css" />
</head>

<body style="width: 100%; height: 90%; background-color: #190061">
  <!-- All of the Node.js APIs are available in this renderer process. -->

  <div class="main">
    <h1>Easy Track | Publication Manager</h1>
    <br />
    <p>Manage your publications and submissions with ease!</p>
    <br />
    <div id="form" style="margin:auto">
      <h2>Add Publication</h2>
      <div class="input-container">
        <i class="blueB"></i>
        <input id="publicationNameTextField" class="input-field" type="text" placeholder="Publication Name" name="publicationName"
          list="publicationNameDataList" />
        <datalist id="publicationNameDataList"> </datalist>
      </div>

      <div class="input-container">
        <i class="blueB"></i>
        <input id="publisherNameTextField" class="input-field" type="text" placeholder="Publisher Name" name="publisherName"
          list="publisherNameDataList" />
        <datalist id="publisherNameDataList"> </datalist>
      </div>

      <div class="input-container">
        <i class="blueB"></i>
        <input id="publicationStatusTextField" class="input-field" type="text" placeholder="Status" name="publicationStatus"
          list="statusList" />
        <datalist id="statusList">
          <option>Awaiting</option>
          <option>Denied</option>
          <option>Accepted</option>
        </datalist>
      </div>

      <div class="input-container">
        <i class="blueB"></i>
        <input id="publicationDateSubmittedTextField" class="input-field" type="text" placeholder="Date Submitted" name="publicationDateSubmitted"
          list="publicationDateSubmittedDataList" />
        <datalist id="publicationDateSubmittedDataList"> </datalist>
      </div>

      <div class="input-container">
        <i class="blueB"></i>
        <input id="publicationDateResponseTextField" class="input-field" type="text" placeholder="Date of Response"
          list="publicationDateResponseDataList" name="publicationDateResponse" />
        <datalist id="publicationDateResponseDataList"> </datalist>
      </div>

      <button id="submitButton" class="btn">Submit</button> <br />
    </div>
    <br />
    <br />

    <div class="PublicationsShow">
      <input type="text" id="myInput" onkeyup="searchBar()" placeholder="Search" />
      <br />
      <i id="clearAllButton" class="fas fa-trash-alt trashHover"></i>
      <p id="clearItemText">Clear All Items</p>

      <table id="myTable">
        <tr class=" header">
          <th style="width:15%; color: white !important;">
            Publication name
          </th>
          <th style="width:15%; color: white !important;">Publisher Name</th>
          <th style="width:15%; color: white !important;">Status</th>
          <th style="width:15%; color: white !important;">Date Submitted</th>
          <th style="width:15%; color: white !important;">
            Date of Response
          </th>
          <th style="width:15%; color: white !important;">Change</th>
        </tr>
      </table>
    </div>
  </div>
  <script>
    // You can also require other files to run in this process
    require("./js/renderer.js");



    function filterTable(event) {
      var filter = event.target.value.toUpperCase();
      var rows = document.querySelector("#myTable tbody").rows;
      for (var i = 1; i < rows.length; i++) {
        var firstCol = rows[i].cells[0].textContent.toUpperCase();
        var secondCol = rows[i].cells[1].textContent.toUpperCase();
        var thirdCol = rows[i].cells[2].textContent.toUpperCase();
        var fourthCol = rows[i].cells[3].textContent.toUpperCase();
        var fifthCol = rows[i].cells[4].textContent.toUpperCase();
        if (
          firstCol.indexOf(filter) > -1 ||
          secondCol.indexOf(filter) > -1 ||
          thirdCol.indexOf(filter) > -1 ||
          fourthCol.indexOf(filter) > -1 ||
          fifthCol.indexOf(filter) > -1
        ) {
          rows[i].style.display = "";
        } else {
          rows[i].style.display = "none";
        }
      }
    }
    document
      .querySelector("#myInput")
      .addEventListener("keyup", filterTable, false);

  </script>
</body>

</html>

sn-p 并不完全准确,因为我的应用程序是通过 Node 和 Electron 运行的。

如果我还不够清楚,请随时向我提问以消除困惑。

如果您对此有任何解决方案,或者对我的不良代码和实践有任何提示,我很感激任何反馈。

谢谢。

【问题讨论】:

    标签: javascript html node.js local-storage electron


    【解决方案1】:

    经过进一步检查,我发现了问题所在。按钮上的点击事件已在会话中分配,但本地存储无法存储这些事件,因为它们不是字符串。

    解决这个问题:

    将您的点击事件留在添加按钮上,以便它们在会话期间起作用,但在页面加载时为您希望使用的按钮添加一个 for 循环。确保在单击按钮期间为元素分配一个类,以便在页面加载时引用它。

    例如

    window.onload = function() {
      var savedInner = localStorage.getItem("listStorageInner");
      var savedOuter = localStorage.getItem("listStorageOuter");
    
      // If there are any saved items, update our list
      if (savedInner) {
        let targetList = document.getElementById("projectList");
        targetList.innerHTML = savedInner;
      }
      if (savedOuter) {
        let targetList = document.getElementById("projectList");
        targetList.outerHTML = savedOuter;
      }
    
      var removeButtons = document.getElementsByClassName("removeMeBtn");
    
      for (let i = 0; i < removeButtons.length; i++) {
        removeButtons[i].addEventListener(
          "click",
          (function() {
            return function() {
              let parent = this.parentElement;
              parent.parentElement.removeChild(parent);
              let targetList = document.getElementById("projectList");
              localStorage.removeItem("listStorageInner", targetList.innerHTML);
              localStorage.removeItem("listStorageOuter", targetList.outerHTML);
              localStorage.setItem("listStorageInner", targetList.innerHTML);
              localStorage.setItem("listStorageOuter", targetList.outerHTML);
            };
          })(i),
          false
        );
      }
    
      var editBtns = document.getElementsByClassName("editMeBtn");
    
      for (let j = 0; j < editBtns.length; j++) {
        editBtns[j].addEventListener(
          "click",
          (function() {
            return function() {
              let parent = this.parentElement;
              document.getElementById("entryInput").value = parent.textContent;
              parent.focus();
              parent.parentElement.removeChild(parent);
              let targetList = document.getElementById("projectList");
              localStorage.removeItem("listStorageInner", targetList.innerHTML);
              localStorage.removeItem("listStorageOuter", targetList.outerHTML);
              localStorage.setItem("listStorageInner", targetList.innerHTML);
              localStorage.setItem("listStorageOuter", targetList.outerHTML);
            };
          })(j),
          false
        );
      }
    };
    

    for 循环遍历所有具有按钮类名的元素,然后在页面加载时分配 onclick 事件。这样,按钮单击事件始终有效并通过本地存储正确保存。此外,在使用本地存储时,请务必注意范围。

    如果其他人遇到此问题,希望这会有所帮助。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-10-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-07-07
      相关资源
      最近更新 更多