同事報案,在「以 MVVM 清單實作資料編輯介面」的經典應用場景(Knockout版範例Angular版範例)遇見怪事。新増一筆資料後,將焦點移至 <input type="text"> 輸入欄位,若按下 Enter 資料會莫名消失,按一次消失一筆…

程式用了 jQuery、Bootstrape、Knockout、KendoUI,加上一堆自訂程式庫,無法斷定是誰造成,只好抽絲剝繭,以能重現問題為原則,將掛載的程式庫及 DOM 元素一一拆除。歷經一番功夫,最後竟發現是個 HTML 基本觀念,某自以為資深的網頁設計老鳥,乖乖上了一課。

用一個超精簡範例重現問題:Live Demo

將焦點停在 Input A,按下 Enter 鍵會觸發 Button A 的 onclick 事件;但同樣狀況則不會發生在 Input B 與 Button B 上,關鍵在於 Input A 與 Button A 被包在 <form></form> 之中,而 Input B / Button B 沒有:

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <title>Enter on form</title>
</head>
<body>
  <form>
  <fieldset>
    <legend>Inside Form</legend>
      <input type="text" value="Input A"/>
      <button onclick="alert('Button A Clicked');return false;">Button A</button>
  </fieldset>
  </form>
  <fieldset>
      <legend>Outside Form</legend>    
      <input type="text" value="Input B"/>
      <button onclick="alert('Button B Clicked')">Button B</button>
  </fieldset>
</body>
</html>

追究原因,「在輸入欄位按 Enter 送出表單」幾乎是所有瀏覽器的預設行為(感覺是網頁設計基本常識,但先前以寫 AJAX 跟 SPA 為主,碰 Form 的經驗不夠多,沒遇過還真就沒學到),Enter 送出表單可以理解,但瀏覽器送出前還幫忙按下 <form> 裡的第一顆按鈕倒是出乎意料。(在以上範例,Button A onclick alert 完要 return false,不然會觸發表單送出行為)再回頭觀察一開始的展示,按 Enter 被刪除的永遠是第一筆,由此可證。

2017-6-29補充: 貼文後不少網友提醒我 <button> 在各瀏覽器的預設 type 可能不同,而我這也才發現對 Chrome 與 IE 而言,<button> type 預設為 submit,是按 Enter 會連帶觸發按鈕的原因,改為 type="button" 後不再被 Enter 觸發點擊,但在這個案例中要防止表單被送出。感謝大家的回饋~(再上一課)

至於解決方案,用 prevent enter submit form 可以 Google 到一大票詢問與討論,常見做法是攔截 document 或 input 的 keypress 事件,在遇到 Enter 鍵時取消動作。但本案例倒不用這麼麻煩,該段程式以 AJAX 方式運作,用不到 <form> ,是因為寫在 ASP.NET WebForm 才被包在 <form> 中,只需將該段 HTML 移至 <form> 之外,問題即刻消失。

撇開這次遇到的特殊狀況,回到「按 Enter 會送出 Form 」行為上,其實存在爭議。Stackoverflow 上有一堆人詢問如何取消,卻也有人強力主張不該改掉(The Enter Key should Submit Forms, Stop Suppressing it),我則喜歡 StackExchange 的這篇觀點,作者以 Facebook 提供 Press Enter to send 選項為例(過去式 ,現已改版),認為交由使用者決定才是最佳選擇,附議!


Comments

# by 我的驗證碼好難算QQ

<button type=button> 試試看?

# by ooxx

"我的驗證碼好難算QQ" 的解法也是我的作法 將 button 明確的設定為 type=button 就可以了 否則預設 type=submit (若你不希望他在form中預設有submit的行為) https://developer.mozilla.org/en-US/docs/Web/HTML/Element/button

# by Jeffrey

to 我的驗證碼好難算QQ, ooxx, 在FB上有網友提到各瀏覽器對<button>的預設type不同,而我這才發現Chrome <button> type預設為submit(再上一課),改成type=button就不會Enter被觸發,但仍要防止表單被送出。感謝回饋。

Post a comment