我寫了一小段程式讓一群Checkbox具有單選的限制。理論上,單選改用Radio就好了,但在我接觸的一些需求中,使用者就是偏好方格打勾的呈現方式,比較貼近傳統紙張表單設計。

程式碼挺簡單的,利用class將幾個Checkbox歸成同一群,當其中任何一個被點選時,就將整群的Checkbox先全設為未勾選,只保留被點選者。

for (var i = 1; i <= 3; i++) 
    $("body").append(
        "<input type='checkbox' class='grpCbx' value='" + i + "' />" +
        "<span>OPTION " + i + "</span>");
$(".grpCbx").click(function() {
    $(".grpCbx").removeAttr("checked");
    this.checked = true;
});
$("<input type='button' value='TEST'>").appendTo("body")
.click(function() { $(".grpCbx:eq(1)").click(); });

(註: 以上的程式碼可以直接拿到Mini jQuery Lab玩)

不過,程式執行結果跟我想像的有些出入。我發現如果用滑鼠點選Checkbox時,操作反應正常,的確具有單選效果。但如果我透過另一個Button點選事件呼叫Checkbox的click(),其他已勾選的Checkbox是會被清除,但指定的Checkbox卻沒有如預期被勾選。

如果將this.checked = true;移除,則以.click()觸發會成功,直接點選反而失敗,直覺上好像內部某種this.checked = !this.checked機制在左右結果,但我推理不出現象背後的邏輯。

詭異的測試結果讓我苦思好久,終於在加了一行alert(this.checked)測試後解開謎團...

我將程式碼改成$(“.grpCbx”).click(function() { alert(this.checked); $(“.grpCbx”)… 分別點擊及程式呼叫,就突顯出差異來。當手動點擊時,在click事件的一開始,this.checked == true;而由程式呼叫click()時,事件一開始時則this.checked == false。

我的推論是:

在手動點選時,Browser先將checked設為true才呼叫click事件函數,如果我清除了全部checked又沒將被點者的設定回true,就會導致勾選失效;而程式以click()觸發時,事件中所見this.checked仍是false,似乎在click事件函數完成後才進行this.checked = !this.checked的動作,我將checked設成true,反而會讓最終結果變成false。

回頭考慮程式修改,才發現原本的寫法很笨--"先將全部清除,再重設被點選者"。為何不只清除點選者以外的Checkbox就好了呢? jQuery有個很棒的API--not(),可以傳入selector、元素或元素陣列,寫成not(this)立刻一步到位。程式改成如下寫法,精簡又有效率,早該如此。

$(".grpCbx").click(function() {
    $(".grpCbx").not(this).removeAttr("checked");
});

Comments

# by 月讀

$(".grpCbx:eq(1)").triggerHandler('click'); 嘗試一下。

# by 月讀

$(this).siblings().removeAttr("checked"); 嘗試一下。

# by Jeffrey

to 月讀, 謝謝您的補充。triggerHandler的點子不錯(我壓根把它忘了,呵,謝謝提醒),只觸發事件函數而不真的執行Browser的預設行為,足以避開問題。siblings()在其餘同群Checkbox與被點選者同一階層且未混雜其他非同群Checkbox的情境裡也適用。

# by colin

我很欣賞也很敬佩JQuery 不過由於本著練功心態 所以JS程式碼還是都由自己編寫成函式或建構式使用 不過我也不知道這樣的決定是好是壞 我個人以為站在巨人肩上學程式 有時候會少學很多細節 但是會省很多時間 不知道前輩對我看法有沒有什麼建議

# by Dickson

$(".grpCbx").not(this).attr("checked",false); 可能會更好,不一定需要用removeAttr

# by Jeffrey

to Dickson, 若依HTML規格,以Attribute標示checked時,有三種表示方法: <input checked>, <input checked="checked">, <input checked=""> [參考: http://www.w3schools.com/tags/att_input_checked.asp] 依我的理解,removeAttr("checked")較嚴謹一些。.attr("checked", false)之所以可行應是jQuery .attr()/.prop()雙管道支援的結果,但已不建議使用(這在1.6推出時曾引發小小的風暴,可參考: http://blog.darkthread.net/post-2011-05-13-jquery-1-6-1.aspx,attr("checked")為紅字項目),但我認為若修改成.prop("checked", false),確實可行,謝謝你的回饋!

Post a comment