标签
HTML必填欄位被跳過:submit()與requestSubmit()送出表單的差別
聯絡表單的信箱明明設了 required,使用者按原本的送出按鈕也會看到提示;換成JavaScript控制的按鈕後,空白資料卻直接送走。先找程式是不是呼叫了 form.submit()。這個方法會略過瀏覽器的欄位驗證,也不會觸發表單的 submit 事件。 如果你要的是「由程式發起一次正常送出」,通常應使用 form.requestSubmit()。它會走驗證與submit事件流程,但仍要核對表單是否設了略過驗證的屬性,以及事件處理器是否取消送出。 兩個方法,差在送出前經過哪些步驟 submit() 直接啟動表單送出,不經互動式欄位驗證,也不派發submit事件。把必填檢查、送出前確認或資料整理全放在submit監聽器裡,這些程式也會被繞過。 requestSubmit() 則會先做正常的限制驗證。若必填信箱空白或格式不符,瀏覽器阻止送出;驗證通過後才觸發submit事件。事件裡若呼叫 event.preventDefault(),正常的表單導向仍會被取消,例如改由你自己的非同步程式處理。 所以「看見submit事件」與「伺服器收到並接受資料」是兩件事。後端仍要檢查欄位、權限及請求是否合法,不能依賴瀏覽器的required保護。 先看表單與指定的送出按鈕 下面是詢問表單的最小結構。信箱欄位有name、type與required;送出按鈕則帶有 intent=inquiry,供後端辨識這次操作。請把action換成自己測試站的接收路徑,別直接拿客戶表單測空白送出。 <form id="inquiry" action="/inquiry" method="post"> <label>信箱 <input name="email" type="email" required> </label> <button id="send" type="submit" name="intent" value="inquiry">送出詢問</button> </form> 程式若要沿用這顆按鈕的送出行為,先取得表單與按鈕,再傳給requestSubmit。這段應放在元素已建立後執行,例如載入於頁尾或使用defer的腳本。 const form = document.querySelector('#inquiry'); const send = document.querySelector('#send'); form.requestSubmit(send); 傳入的必須是這份表單所屬的submit按鈕;一般 type="button" 按鈕不能當這個參數。指定send後,這顆按鈕的name/value會參與送出,submit事件的 event.submitter 也能識別它;按鈕上的formaction或formmethod等覆寫設定同樣需要核對。 空白、合法值與按鈕參數,分三次比較 在自己的練習頁加一個submit監聽器,先只記錄事件,不取消正常送出。開著瀏覽器開發者工具的Console與Network,再做以下比較;示範信箱使用保留測試網域 [email protected]。 form.addEventListener('submit', (event) => { console.log('submit事件', event.submitter); }); 第一次,保持信箱空白,呼叫requestSubmit(send)。 應看見欄位提示,沒有submit事件,也沒有這次正常表單請求。若空白仍送出,先查form上的novalidate與按鈕上的formnovalidate,不要只看required是否存在。 第二次,仍保持空白,呼叫submit()。 在這個沒有其他攔截的普通表單裡,瀏覽器會送出空信箱,submit監聽器不會執行。這正是兩個方法的行為差別;不要拿正式表單做這一步。 第三次,填入合法信箱,呼叫requestSubmit(send)。 此時會經過submit事件,submitter指向send,請求包含按鈕的intent值。接著比較不帶參數的 requestSubmit():它仍會驗證及觸發submit事件,但不會自動挑選那顆send按鈕,該按鈕的name/value也不會因此加入。 改過方法還是不對,查這三個位置 先檢查是否在form上放了 novalidate,或指定按鈕帶著 formnovalidate。這些屬性會影響正常驗證流程,改成requestSubmit也不代表強制把它們取消。 再找submit事件內有沒有 preventDefault()。如果有,檢查後續程式是否真的發出請求、失敗時有沒有恢復按鈕;不要因為沒有頁面導向,就判定requestSubmit無效。 最後核對欄位命名。把某個控制項的name或id設為 submit,可能遮住表單的submit方法,呼叫時出現「submit is not a function」。避免使用會碰到表單API的欄位名,先改成email、message等有實際意義的名稱。 若你的問題是「按鈕放進form就意外送出」,先看 HTML按鈕type的設定;本篇處理的是程式主動送出時的驗證流程,兩個入口要分開查。 參考資料...
HTML寫了checked=”false”還是勾選:分清屬性與目前狀態
模板輸出checked="false",核取方塊卻還是打勾?在原生HTML裡,checked是布林屬性;寫進標籤就表示預設勾選,不會把字串false當成關閉指令。若要預設不勾選,應該省略整個checked屬性。 false不是checked的合法關閉值 先把下面兩個欄位放進一個空白頁,比較初始畫面。第一個是常見的錯誤輸出,第二個才是預設不勾選的寫法。 <!-- 錯誤示範:仍會預設勾選 --> <label> <input type="checkbox" checked="false"> 接收更新通知 </label> <!-- 預設不勾選:不輸出checked --> <label> <input type="checkbox"> 接收更新通知 </label> 布林屬性可只寫名稱,例如checked;也可寫checked=""或checked="checked"。字串true和false都不是合法取值。瀏覽器仍會因為屬性存在而把第一個方塊設為預設勾選,但不要把這種容錯行為當成正確格式。 模板應決定是否輸出整個屬性 檢查模板最後送到瀏覽器的HTML。當設定為關閉時,應得到沒有checked的input,而不是checked="false"或checked="0"。若資料來自資料庫或API,先依資料格式把它轉成真正的布林值,再決定是否輸出checked;別直接把字串塞進屬性。 這裡說的是原生HTML。框架的屬性綁定有自己的語法與轉換規則,不能把原始碼中的綁定表達式直接當成最後的HTML。先看瀏覽器裡實際產生的元素,再查該框架的綁定文件。 頁面載入後,讀checked目前狀態 如果要在JavaScript裡取消勾選,用元素的checked屬性,給它布林值false。以下HTML與後面的程式碼可接在一起測試;script放在表單後面,確保先取得元素。 <form id="demo"> <label> <input id="notice" type="checkbox" checked> 接收更新通知 </label> <button type="reset">重設表單</button> </form> const notice = document.querySelector('#notice') notice.checked = false console.log(notice.checked) // false:目前狀態 console.log(notice.defaultChecked) // true:預設狀態 console.log(notice.hasAttribute('checked')) // true 使用者手動取消勾選時,HTML上的checked也不一定消失。判斷「現在有沒有勾選」應讀notice.checked,不要用getAttribute('checked')或屬性是否存在來代替。 重設後又勾選,先查預設狀態 在上面的表單按「重設表單」,方塊會回到預設勾選。notice.checked=false只改了當下狀態,沒有把HTML的預設值一起改掉。若需求是連重設後也維持預設不勾選,就要另外調整預設狀態;不要只在畫面上取消一次便以為完成。 還要分清checked與value。value是欄位勾選並提交時使用的值,不是打勾開關。一般表單中,未勾選的checkbox不會提交該欄位的名稱與值;後端若需要明確的關閉值,須按自己的資料格式處理,不能期待checked="false"替你送出false。 參考資料 MDN:HTML布林屬性的合法寫法 MDN:checked與defaultChecked MDN:checkbox預設狀態及提交值
