2011年1月27日 星期四

jQuery 無法同時使用 .change() 與 .keyup()

在修改一段 jQuery 程式時,發現如果同時去攔一個物件的 .change() 與 .keyup() 事件,會造成 .change() 失效。譬如以下面這段程式來說,理論上,你在輸入方塊敲字時,應該都會觸發 .change() 與 .keyup(),但事實卻不然!

<html>
<head>
<script src="http://code.jquery.com/jquery-1.4.4.js"></script> 
<script>

  $(function(){

       $(".upper").keyup(function(evt){
   alert('keyup');
       }).change(function(e){
          alert('change');
       });
   });

</script>
</head>
<body>
<input type="text" id="tbxTest1" class="upper" >

</body>
</html>

jQuery 的 .change() 與 .keyup() 事件對應到 javascript 分別是 onchange 與 onkeyup。在過去,這兩位 onchange 與 onkeyup 就已經是水火不容了,而在 jQuery 也是依然死性不改。關於這一點,可以參考微軟的解釋:官網出處

This event is fired when the contents are committed and not while the value is changing. For example, on a text box, this event is not fired while the user is typing, but rather when the user commits the change by leaving the text box that has focus. In addition, this event is executed before the code specified by onblur when the control is also losing the focus.
The onchange event does not fire when the selected option of the select object is changed programmatically.
所以,為了避免這兩個天生的冤家,建議如果您不嫌棄.blur() 的話, 將 .change() 改成 .blur(),就可以順利執行了。

2011年1月18日 星期二

讓 <span> 可以設定寬度

指定了寬度給 <span> ,沒想到竟然一點效果也沒有。後來經高人指點後,原來還要搭配 float:left 的樣式,才會正常。但實際上的頁面並非只有一個<span>而已,加上 float 之後,會讓其他原本正常的頁面排版出現怪異的行為。後來發現,還有另一個樣式要一起使用,clear:left。也就是說,當你希望頁面上的某個區塊呈現浮動效果時,可以使用 float,但後面的部份,如果不再需要浮動效果時,則記得用 clear 來停止。

測試程式如下:

<html>
<head>
<style>
.sp
{
  float:left;
  width:20px;
  border-style:none;
  background-color:red;

}
.full
{
  float:left;
  width:60px;
  border-style:none;
  background-color:yellow;

}

.myDiv
{
clear:left;
}

</style>
</head>
<body>

<div class="myDiv"><span  class="full" >第一行</span></div>
<div class="myDiv"><span class="sp">1</span><span class="sp">2</span><span class="sp">3</span></div>
<div class="myDiv"><span  class="full" >最末行</span></div>
</body>
</html>
在 FireFox , Chrome 呈現的結果是正確的,但在 IE 就會出現一個很討厭的小地方,就是每一個 Div 的行距空白空的很明顯,如下圖。在 FireFox 與 Chrome 並不會出現空白。

為了解決 IE 這問題,在網路上找到可以用 display:inline 這樣式來處理。果真,IE 可以透過 display:inline 來解決,但...現下又換成 FireFox 、 Chrome 不行了。很想哭...

在「解決IE6、IE7、IE8、Firefox CSS兼容性的 Hack 写法」提出了解決不同瀏覽器處理 CSS 的作法,於是我讓 display:inline 只讓 IE 去使用,其他瀏覽器不准。這樣,還真的完整地把問題告一段落了。

最後修改的程式:

<html>
<head>
<style>
.sp
{
  float:left;
  width:20px;
  border-style:none;
  background-color:red;

}
.full
{
  float:left;
  width:60px;
  border-style:none;
  background-color:yellow;

}

.myDiv
{
clear:left;
*display:inline; //只針對 IE
}

</style>
</head>
<body>

<div class="myDiv"><span  class="full" >第一行</span></div>
<div class="myDiv"><span class="sp">1</span><span class="sp">2</span><span class="sp">3</span></div>
<div class="myDiv"><span  class="full" >最末行</span></div>
</body>
</html>

補充:
20110708
遇到一個特別的情況,當內容有中文時,IE8畫面顯示會不正常,但 FireFox,Chrome 可以。如果都是英文,則 IE 就正常了。因緣際會的看到 「IE在CSS中的因中文字體的錯誤」,試著也將 style 加上 「style='font-family:細明體'」 的設定,則 IE8 畫面就會正常。真是無言....

Reporting Service R2 設定每頁的標頭都可重複

在 Reporting Service 2005 的年代,要讓 Table 的標頭在每一頁都可以重複出現,只要設定屬性「Repeat Column Headers」就可完成,但在 Reporting Service 2008 R2 卻不行。如果你也同樣有這困擾,不妨試試以下作法。

首先,在群組視窗裡右下角有個倒三角形,點選後選擇「進階模式」。


接著,點選資料列群組的「(靜態)」,並在屬性視窗中將 RepeatOnNewPage 設成 True。


完成以上兩個動作後,你的報表每一頁就可以重複出現表頭了。也許你會納悶,為何這麼簡單的事情要弄的這麼複雜?我也深有同感,或許,下個版本的 Reporting Service 會更人性些吧。




參考:Tablix headers not repeating in SSRS 2008

2011年1月14日 星期五

透過 jQuery 取得 Asp.Net 裡 CheckBoxList 被勾選的文字

恰巧同事問了個問題,覺得蠻有趣的,所以也分享一下。

使用 Asp.Net 的 CheckBoxList,只要你設定好 DataSource 之後,.Net 會自動幫你把所有資料呈現出來,畫面如下所示:
.Net 所產生的網頁原始碼為:

<table id="cb">

<tr>

<td><input id="cb_0" type="checkbox" name="cb$0" value="1" />
<label for="cb_0">paladin</label></td>

</tr><tr>

<td><input id="cb_1" type="checkbox" name="cb$1" value="2" />
<label for="cb_1">ltt</label></td>

</tr><tr>

<td><input id="cb_2" type="checkbox" name="cb$2" value="3" />
<label for="cb_2">lee</label></td>

</tr>

</table>


目前的需求,是要將被勾選項目的文字顯示出來,因為每一個項目都已經被指定了預設的ID,但又不想透過 Server 端去處理以避免觸發 PostBack,所以希望只從前端用 javascript 就能取出有被勾選的項目文字。依上述的 HTML 原始碼,如果要從
<input id="cb_0" type="checkbox" name="cb$0" value="1" />
裡面去取得有被勾選的文字「paladin」真的還有點困難,因為 .Net 所產生的 Html Code 根本就沒有把 「paladin」放到 input 標籤裡。這時,自己為 input 標籤加上自訂的屬性或許是個可行的方法,所以在 CheckBoxList 的 PreRender 事件裡,把項目文字的內容也給他加上去。但是,之後的發展,更是令人意外啊~

protected void cb_PreRender(object sender, EventArgs e)
{
    foreach (ListItem li in cb.Items)
    {       
       li.Attributes["text"] = li.Text;
    }
}

Html Code:
<table id="cb">

 <tr>

  <td><span text="paladin"><input id="cb_0" type="checkbox" name="cb$0" value="1" /><label for="cb_0">paladin</label></span></td>

 </tr><tr>

  <td><span text="ltt"><input id="cb_1" type="checkbox" name="cb$1" value="2" /><label for="cb_1">ltt</label></span></td>

 </tr><tr>

  <td><span text="lee"><input id="cb_2" type="checkbox" name="cb$2" value="3" /><label for="cb_2">lee</label></span></td>

 </tr>

</table>

原先每個 checkbox 相關的 Html Code,現在變成最外層被包了一個 <span> 標籤,而剛剛所加的項目名稱也是被產生在這個<span> 標籤裡。

<span text="paladin">**原先的 checkbox html**</span>

依據上面新的 Html Code,要取出被勾選項目,則可以用 jQuery 的

$("input[type=checkbox]:checked").each(...); 來完成;
 [參考]JQuery 取得 checkbox 群組內被選取的項目

至於要取得項目名稱,則需透過 jquery 的 .parent( ) ,來取得最外一層 <span> 標籤裡的內容了。

於是,我在前端 .aspx 頁面定一了一段 JavaScript Function:
<script>
function ShowData() {             
    var str = "";
    $("input[type=checkbox]:checked").each(function (i) {
        str = str + $(this).parent().attr("text") + ",";
    });
    alert(str);             
}
</script>
ShowData( ) 主要目的,就是取得目前頁面上所有被勾選的 checkbox ,並將他們父親的 text 屬性內容存到 str 變數中,最後並將結果顯示出來。

最後,為了方便測試,替每個 checkbox 加入 onclick 事件:

<script>
$(function () {            
    $("input[type=checkbox]").click(function () { ShowData(); });
});
</script>

經過這番調整後,就可以正確顯示想要的內容了。


這件事,讓我釐清了 Asp.Net 對於 CheckBoxList 於前端所產生的 Html Code,並非如我想像中的單純,他的設計上多了些其他考量,雖然我還沒辦法理解他的用心到底所為何事,但可以確定的是,這問題多花了無辜的使用者好幾個小時在找蟲,也希望有緣人在有幸之年能看到這篇文章後,省去摸索時間,留下來好好去泡泡茶、去看電視、去打電動,不是更有意義嗎?

[補充 20120706]
也可以透過 .next 來處理這問題。可以參考:
透過 jQuery 取得 Asp.Net 裡 CheckBoxList 被勾選的文字(二)

2011年1月6日 星期四

強迫使用者輸入大寫或小寫字母

讓使用者乖乖在輸入方塊上敲大寫或小寫字母,似乎是不可能的事,那要如何霸凌使用者所輸入的資料呢?目前我整理了兩種前端的使用方法。

第一種方式,是透過 jQuery 與 javascript。在 javascript 裡有兩個 function: toUpperCase() 、toLowerCase(),分別是將字串轉為大寫或小寫。我攔截使用者敲鍵盤的 keyup 事件,並在這事件裡進行轉換的動作。最後用 jQuery 尋找所有有定義 class 名稱為 upper 或 lower 的物件,可以適用這次的調整。

第二種方式,是透過 style 屬性裡的 text-transform 來產生大寫或小寫的效果,舉例來說,標記為 style="text-transform: uppercase",則你輸入的文字都會自動被轉成大寫,而 style="text-transform: lowercase" 則是小寫。

以上兩種方式都能符合自己的需求,但使用 style 的作法相較之下,真的簡單多了。


<html>
<head>
<script src="http://code.jquery.com/jquery-1.4.4.js"></script> 
<script>

  $(function(){

       $(".upper").keyup(function(evt){
          var vOri=$(this).val();
          var vNew=vOri.toUpperCase();
          $(this).val(vNew);
       });

       $(".lower").keyup(function(evt){
          var vOri=$(this).val();
          var vNew=vOri.toLowerCase();
          $(this).val(vNew);
       });
   });

</script>
</head>
<body>
ToUpper(JQuery):<input type="text" id="tbxTest1" class="upper" ><br>
ToLower(JQuery):<input type="text" id="tbxTest2" class="lower" ><br>
ToUpper(Style):<input type="text" id="tbxTest3" style="text-transform: uppercase" ><br>
ToLower(Style):<input type="text" id="tbxTest4" style="text-transform: lowercase" ><br>

</body>
</html>


補充:20110106

經過實際專案的測試,發現上述兩種方式,實際上是有點差異的。我先說透過 style 屬性的方式,這方式只是讓你的結果看起來像是已經轉換成大寫或小寫,但實際不是。所以如果你不介意儲存資料時是否一定要是大寫或小寫,那使用 style 屬性的方式並無太大問題。反之,如果你很在意存入資料庫時必須是大寫或小寫,那就不可以用 style 屬性方式了,得採用 jquery + javascript。


在上圖中,我每個輸入方塊都是輸入 aaaaa  ,壓下 btn 按鈕並將畫面上的值印出來。可以發現 ToUpper(JQuery) 的值是符合我的期待,但 ToUpper(Style)就不同了,畫面上顯示 AAAAA,但它裡面的結果卻還是我原先輸入的 aaaaa。所以,在使用這轉大小寫功能時,得留意這兩者用法的差別了。



Ref:
01.JavaScript toUpperCase() Method
http://www.w3schools.com/jsref/jsref_touppercase.asp
02.How can I force input to uppercase in an asp.net textbox?
http://stackoverflow.com/questions/202368/how-can-i-force-input-to-uppercase-in-an-asp-net-textbox