關於Checkbox Click事件的小發現

我寫了一小段程式讓一群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");
});
歡迎推文分享:
Published 29 May 2009 08:25 PM 由 Jeffrey
Filed under: ,
Views: 31,416



意見

# 月讀 said on 30 May, 2009 02:33 AM

$(".grpCbx:eq(1)").triggerHandler('click');

嘗試一下。

# 月讀 said on 30 May, 2009 02:50 AM

$(this).siblings().removeAttr("checked");

嘗試一下。

# Jeffrey said on 30 May, 2009 10:11 AM

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

# colin said on 18 January, 2010 01:08 AM

我很欣賞也很敬佩JQuery

不過由於本著練功心態 所以JS程式碼還是都由自己編寫成函式或建構式使用

不過我也不知道這樣的決定是好是壞

我個人以為站在巨人肩上學程式 有時候會少學很多細節

但是會省很多時間

不知道前輩對我看法有沒有什麼建議

# Dickson said on 29 October, 2012 02:30 AM

$(".grpCbx").not(this).attr("checked",false);

可能會更好,不一定需要用removeAttr

# Jeffrey said on 29 October, 2012 05:40 AM

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

你的看法呢?

(必要的) 
(必要的) 
(選擇性的)
(必要的) 
(提醒: 因快取機制,您的留言幾分鐘後才會顯示在網站,請耐心稍候)

5 + 3 =

搜尋

Go

<May 2009>
SunMonTueWedThuFriSat
262728293012
3456789
10111213141516
17181920212223
24252627282930
31123456
 
RSS
創用 CC 授權條款
【廣告】
twMVC
最新回應

Tags 分類檢視
關於作者

一個醉心技術又酷愛分享的Coding魔人,十年的IT職場生涯,寫過系統、管過專案, 也帶過團隊,最後還是無怨無悔地選擇了技術鑽研這條路,近年來則以做一個"有為的中年人"自許。

文章典藏
其他功能

這個部落格


Syndication