我有一個表單,它通過 PHP 將影像檔案名和其他資訊提交到 MySQL 資料庫,該資料庫在后端都可以正常作業。在前端,我使用 JavaScript fetch()API 來確保在執行某些功能時不會硬重繪 頁面(特別是如果在提交表單之前洗掉了影像)。
當使用.remove-image按鈕洗掉影像組件時,下面的 JavaScript 會阻止頁面執行硬重繪 ,然后它還會根據需要洗掉影像組件的 HTML。但是,當主表單提交發生時,此代碼會產生副作用:
問題
當通過.upload-details按鈕提交主表單時,這也受到fetch()代碼的影響。我只希望在單擊洗掉按鈕時觸發獲取代碼,而不是在單擊主提交按鈕時觸發。我想我可以通過將if (fetchForms) {} 代碼包裝在按鈕上的單擊事件偵聽器中來實作這一點.remove-image,但這也不起作用(我在下面包含了這段代碼)。它似乎仍然觸發e.submitter.closest('.upload-details-component').remove()代碼行?
注意:此問題僅在.remove-image單擊按鈕后發生。如果.remove-image從未單擊該按鈕,則主.upload-details按鈕將正常作業。
我得到的錯誤訊息是'TypeError: Cannot read properties of null (reading 'remove') at app.js:234:77' 這與這行代碼有關e.submitter.closest('.upload-details-component').remove()
我的問題
如何獲取它,以便fetch()代碼僅在單擊洗掉.remove-image按鈕時才有效,而不是在單擊主.upload-details按鈕時,在所有情況下?
當我在.upload-details-component按下主按鈕后進行硬頁面重繪 時,雖然它在控制臺中拋出了錯誤,但表單提交已經發生。所以我想我需要一種在單擊另一個按鈕時關閉 fetch() 的方法?
JavaScript
let fetchForms = document.querySelectorAll('.fetch-form-js'),
removeImageButton = document.querySelectorAll('.remove-image')
// URL details
var myURL = new URL(window.location.href),
pagePath = myURL.pathname
removeImageButton.forEach((button) => {
button.addEventListener('click', () => {
if (fetchForms) {
fetchForms.forEach((item) => {
item.addEventListener('submit', function (e) {
e.preventDefault();
const formData = new FormData(this);
if (e.submitter) {
formData.set(e.submitter.name, e.submitter.value);
}
fetch(pagePath, {
method: "post",
body: formData
})
.then(function(response){
// only remove component if the 'remove-image' button is clicked
e.submitter.closest('.upload-details-component').remove()
return response.text();
// }).then(function(data){
// console.log(data);
}).catch(function (error){
console.error(error);
})
})
});
} // end of if (forms)
}) // 'remove' button clickEvent
}) // removeImageButton forEach
HTML
注意:影像組件是while回圈輸出的,因為它們幾乎總是不止一個。為簡單起見,我只在下面展示了一個組件。
<form class="fetch-form-js" method="post" enctype="multipart/form-data">
<!-- IMAGE DETAILS COMPONENT. THESE COMPONENTS ARE OUTPUTTED WITH A WHILE LOOP -->
<div class="upload-details-component">
<div class="form-row">
<label for="image-title">Image Title</label>
<input id="title-title>" class="input-title" type="text" name="image-title[]">
</div>
<div class="form-row">
<label for="tags">Comma Separated Image Tags</label>
<textarea id="tags" class="text-area" type="text" name="image-tags[]"></textarea>
</div>
<div class="form-row">
<!-- DELETE BUTTON -->
<button name="upload-details-delete" value="12" class="remove-image">DELETE</button>
<input type="hidden" name="image-id[]" value="12">
</div>
</div>
<!-- IMAGE DETAILS COMPONENT - END -->
<div class="form-row upload-details-submit-row">
<button id="upload-submit" class="upload-details" type="submit" name="upload-submit">COMPLETE UPLOADS</button>
</div>
</form>
uj5u.com熱心網友回復:
以下是我對您的高級目標的理解:
- 單擊任何
.remove-image按鈕時,通過取消默認瀏覽器行為(即發布 頁面重定向)來處理它,而是fetch呼叫您的服務器端點,如果成功,則洗掉與已洗掉影像對應的表單部分. - 將行為保持
upload-submit為默認值(即發布 頁面重定向)
讓我先介紹一下您的代碼當前是如何作業的,以及為什么您會看到當前行為:
當頁面加載時,您正在頁面上
.remove-image的所有按鈕上注冊一個“點擊”處理程式:let removeImageButton = document.querySelectorAll(".remove-image"); removeImageButton.forEach((button) => { button.addEventListener("click", () => { // ... }) })每當單擊任何
.remove-image按鈕時,它都會在頁面加載時找到的所有submit表單上注冊一個表單處理程式。當單擊表單中的任何元素(包括按鈕)時,將執行此處理程式。處理程式取消默認的瀏覽器重定向行為,手動執行請求,然后嘗試使用與按下的任何按鈕最近的父元素來提交表單:.fetch-form-js<button type="submit">upload-submitfetchremove.upload-details-component// When the page loads.. let fetchForms = document.querySelectorAll(".fetch-form-js") // After any .remove-button is clicked... fetchForms.forEach((item) => { // ...register this handler on all .fetch-form-js forms. item.addEventListener("submit", function (e) { // When a .fetch-form-js is submitted (including by pressing and upload-submit button... // ...prevent browser redirect... e.preventDefault() // ... // ...execute a fetch request... fetch(/* ... */) // ... and, if successful, hide the .upload-details-component element that is // the closest parent of whatever button was clicked to submit the form. .then( function(response) { e.submitter.closest(".upload-details-component").remove() // ... }) // ... }) })
這里的主要問題是item.addEventListener("submit")處理程式將在所有提交按鈕上執行,包括upload-submit按鈕(您希望保留默認行為)。這正是你不想要的。
第二個問題是,當它因為upload-submit單擊按鈕而執行時,e.submitter.closest(".upload-details-component")將是null(因為沒有.upload-details-component它的父級upload-submit)
這是一種重構方法以避免這兩個問題:
const fetchForms = document.querySelectorAll(".fetch-form-js");
// Simplify things by only registering "submit" events.
fetchForms.forEach((item) => {
item.addEventListener("submit", function (e) {
if (
e.submitter &&
// This will be "true" if the "remove-image" button is clicked to submit the form,
// and false if the ".upload-submit" button is clicked to submit the form.
// This way, you'll keep browser default behavior for the ".upload-submit" button 100% of the time.
e.submitter.classList.contains("remove-image")
) {
e.preventDefault();
const formData = new FormData(this);
formData.set(e.submitter.name, e.submitter.value);
fetch(pagePath, {
method: "post",
body: formData
})
.then(function (response) {
e.submitter.closest(".upload-details-component").remove();
return response.text();
})
.catch(function (error) {
console.error(error);
});
}
});
});
有關作業示例以及與原始代碼的并排比較,請參閱此代碼框。
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/464307.html
標籤:javascript 形式 事件 dom 事件 获取 API
上一篇:表單資料未填寫React
