解決Bootstrap custom-switch無法賦值、取值錯誤問題

今天在使用Bootstrap custom-switch客製化開關元件時,發現在UI層面上的操作並無法影響底層的實際賦值,導致最後Javascript取出時根本就沒有辦法拿到正確、表裡如一的資料,這篇文章就是在介紹如何改善這個問題。

討論並解決Bootstrap custom-control-input值表裡不一的問題

Step 1. 建立一個典型的Bootstrap開關元件

<div class="form-group">
  <div class="custom-control custom-switch">
    <input type="checkbox" class="custom-control-input" id="bIsEnabled">
    <label class="custom-control-label increaseCheckbox" for="bIsEnabled">是否開啟?</label>
  </div>
</div>
<style>
  .increaseCheckbox {
    line-height: 1.5;
    margin-left: 1.4em;
    transform: scale(1.2);
  }
</style>

Step 2. 建立一個按鈕並調用jQuery去讀取這個元件的值,發現出現的是on/off值,以現在的狀況(HTML中根本沒有設定預設值)來說,alert上卻是顯示on。

$(function () {
  $("#btn").click(function () {
    alert($("#bIsEnabled").val());
  });
});

Step 3. 一般來說資料送到後端都是要以boolean型態儲存,所以應該是true/false才對。但沒事,這個鍋不應該是Bootstrap背,這本來就是HTML的規範,只要稍微實作先賦予value屬性true/false就解決,例如:

<input type="checkbox" class="custom-control-input" id="bIsEnabled" value="false">

註:若嫌麻煩也可以透過jQuery在DocumentReady時期就覆寫掉,這樣你就可以不用補value在HTML上了。這類型的元素一多起來,甚至可以透過Selector一次性選取解決。

$("#bIsEnabled").attr("value", false);

Step 4. 這下alert回傳正確的false了,但是我們發現去點選UI的switch開關並不能如實的反應真正的true/false狀態,也就是說jQuery取到的value在此刻永遠為false。

Step 5. 按下F12切換到瀏覽器開發者模式,發現這顆input type="checkbox"元素,就算表面UI在那邊不斷切換,他在背景依然躺平連動都不動一下,這代表Bootstrap在後面並沒有幫我們實作真實數值或狀態的toggle,果然只負責到「表面的顯示」而已。

Step 6. 知道真相後只能再請jQuery好朋友出來幫忙,設定custom-control-input的監聽事件,如果有被點選異動就馬上去把應該賦予的內含值改掉。(這段程式碼比較消耗前端效能,也會因為應用的場域不同而迥異,請自行視需求變更)

$(".custom-control-input").on("change", function (e) {
  $(this).attr("value", e.target.checked).attr("checked", e.target.checked);
});

透過瀏覽器開發者模式我們可以觀察背景的數值的確被賦予正確的HTML屬性了。

上面這張圖是開啟狀態背後的屬性值。

上面這張圖是關閉狀態背後的屬性值。

透過這樣的程式碼增補,可以讓FormData收集表單數值更加直觀便利,以上說明。

補充:HTML jQuery事件監聽的寫法

在早期WebForm的寫法中,我們會很常宣告了一堆ServerControl Buttons,然後透過單一方法來得知是按下哪顆按鈕,進而讓程式碼更精簡,例如:

void button_Click(object sender, EventArgs e)
{ var s = (sender as Button).Text; }

那麼,等效的程式碼在Javascript可以看待成:

$("button").on("click", function (e) {
  var s = e.target.id;
});
Bootstrap CustomControl CustomSwitch CustomControlInput CanNotSetValue GetErrorValue Bug