顯示具有 jQuery 標籤的文章。 顯示所有文章
顯示具有 jQuery 標籤的文章。 顯示所有文章

2019年5月28日 星期二

jQuery 版本升級,多麼痛的領悟


一翻開多年前寫的 Code,當時為了趕流行用了 jQuery 1.6,時光荏苒,現在只是為了安全性而將版本升級到 jQuery 3.4.1,沒想到並不是只有複製貼上這麼簡單,還遇到下面幾個升級過程中所遇到的問題。

我主要是以 Chrome 瀏覽器,F12 打開「開發人員工具」裡的 Console 頁籤,檢視是否有 javascript 錯誤。

一:TypeError: $(...).parents(...).size is not a function

因為 .size() 這語法,在 jQuery 1.8 以後就不再支援了(Ref 01),必須改成用 .length 來取代,所以原先

$(".color").size() 

要改成

$(".color").length

注意,一個是有括號(),屬於方法;一個沒有括號,是屬性。而且使用 .length 的數度還要比 .size() 快上1/3。官網上指出他的差異關鍵,在於 .length 少了 .size() 的函數呼叫的效能消耗(Ref 02)。


其他說明,可參考 Ref 03。

二:Uncaught Error: Syntax error, unrecognized expression: a[href=#]

原來我之前用 jQuery 語法抓取超連結時,使用了類似 $("a[id=#element]") 語法,
現在遇到這種特殊字元需要用括號把它們刮起來。可參考 Ref 04。



$("a[id='#element']")



三:Uncaught TypeError: Cannot read property 'msie' of undefined

早期 jQuery 有提供 jQuery.browser() 這語法,可用來取得使用者目前使用的瀏覽器相關資訊。但在 1.9 版本之後,正式被移除了(Ref 05)。但如果你還是有不得不使用他的情況下,可以自己手動加回去。只要在引用 jQuery 3.4.1 後的位置加上就可以。


<script src="jquery-3.4.1.js"></script>
<script type="text/javascript">
    jQuery.browser = {};
    (function () {
        jQuery.browser.msie = false;
        jQuery.browser.version = 0;
        if (navigator.userAgent.match(/MSIE ([0-9]+)\./)) {
            jQuery.browser.msie = true;
            jQuery.browser.version = RegExp.$1;
        }
    })();
</script>



你可能會想更懶一點,這時可以去下載 jquery-migrate js 來使用,


依據上述情況,就只需改寫成 


<script src="jquery-3.4.1.js"></script>
<script src="jquery-migrate-3.0.1.js"></script>


因為我有使用 colorbox ,而 colorbox 使用的 jQuery 版本很舊,目前也沒有更新版。所以直接使用最新版本的   jquery-migrate-3.0.1.js 並無法解決  'msie'的問題。只好退而求其次的使用 jquery-migrate-1.2.1.min.js。

參考:
Ref 01:jQuery length 和 size()區別總結

Ref 02:.size()

Ref 03:TypeError: $(…).parents(…).size is not a function

Ref 04:Syntax error, unrecognized expression for href

Ref 05:jQuery.browser

2016年8月29日 星期一

使用 jQuery 完成 JSON 資料的傳遞

聽到要透過 JSON 來傳遞資料,心中不免冒出:那不是要寫很多行程式?不是還要引用 JSON 相關的 javascript 模組?不是還要... 總之,就是很煩就是了!

最近看了幾篇 JSON 相關的使用文章後,發現其實不困難,也還蠻簡潔的。或許有很多小細節的地方我還沒發現,但大致上目前會用到的功能,都已經可以達到了。

首先,要先建立一個模擬後端的程式,用來產生 JSON 資料,準備給前端使用,而內容就大概長得像下面這個樣子。


{
"title":"jquery 入門",
"price":"299",
"author":"paladin lee"
}


只是最後要回傳的時候,需將物件序列化成 JSON 格式再回傳,而也只需使用下面這方法就可以了。

System.Web.Script.Serialization.JavaScriptSerializer().Serialize(stringValue)

所以我的後端程式如下:

ser01.ashx

public void ProcessRequest (HttpContext context) {

    StringBuilder sb = new StringBuilder();
    sb.Append(@"{
    ""title"":""jquery 入門"",
    ""price"":""299"",
    ""author"":""paladin lee""
}
");

    //將 sb 物件序列化成JSON格式再回傳
    context.Response.Write(new System.Web.Script.Serialization.JavaScriptSerializer().Serialize(sb.ToString()));
}


接下來要處理的,就是前端了。透過  jQuery 的 getJSON() 方法,可以讓我們輕鬆的接收回傳的 JSON 資料。再透過 $.each() 來一一處理每個項目的內容。

 $.each(data2, function (property, value) {

   //Do something...

 });


從後端所序列化的內容可知,回傳的資料裡面三筆,以第一筆為例, property 是 "title",value 則是 "jquery 入門"。這裡要特別注意,因為回傳的 JSON 資料目前只是被視為字串,要透過 $.parseJSON() 將這 JSON 字串轉為 JSON 物件才能進一步被我們使用。

前端完整的測試程式則如下所示:

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title></title>
    <style>
        .tb  
        {
            border-collapse:collapse ;                  
        }
        
        .tb th
        {
            border:1px solid black;
            padding:5px;
        }
        
        .tb td
        {
            border:1px solid black;
            padding:5px;
        }
        
    </style>
    <script src="js/jquery-1.10.2.min.js" type="text/javascript"></script>
    <script>
        $(function () {
            
            $.getJSON("ser01.ashx", function (data) {

                var vTable = $("<table class='tb' border='1'></table>");
                var vItem01="";

                //convert JSON string, not an object
                var data2 = $.parseJSON(data);

                $.each(data2, function (property, value) {
                    vItem01 = vItem01 + "<tr><th>" + property + "</th><td>" + value + "</td></tr>";
                });                               

                $(vTable).append(vItem01);
                $(".div01").append(vTable);

            });
        });
    </script>
</head>
<body>
    <form id="form1" runat="server">   
    <div class="div01">
    </div>
    </form>
</body>
</html>


而畫面結果就會長成這樣子:


這時,或許你可能會說,我其實想要的,是類似好幾本書的資訊,而不是單單某一本書的詳細內容ㄟ!這其實也不難,首先來產生後端的資料,其內容大概如下:
[
 {
 "title":"jquery 入門",
 "price":"299",
 "author":"paladin lee"
 },
 {
 "title":"html5 入門",
 "price":"199",
 "author":"Nikki"
 },
 {
 "title":"麻將",
 "price"":"99",
 "author"":"jason"
 }
]

同樣地,將他序列化後,就可以直接送出去了。

server02.ashx

public void ProcessRequest (HttpContext context) {
 StringBuilder sb = new StringBuilder();
 sb.Append(@"[
 {
 ""title"":""jquery 入門"",
 ""price"":""299"",
 ""author"":""paladin lee""
 },
 {
 ""title"":""html5 入門"",
 ""price"":""199"",
 ""author"":""Nikki""
 },
 {
 ""title"":""麻將"",
 ""price"":""99"",
 ""author"":""jason""
 }
 ]
 ");
 //將 sb 物件序列化成JSON格式再回傳
 context.Response.Write(new System.Web.Script.Serialization.JavaScriptSerializer().Serialize(sb.ToString()));
}


至於前端的部份,我們則是透過兩次的 $.each() 來把回傳的 JSON 資料解析出來。
$.each(data, function () { 
 //處理每一筆的資料
 $.each(this,function(property, value){
  //處理每一個欄位的資料
 });                    
});



完整前端程式如下:

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title></title>
    <style>
        .tb  
        {
            border-collapse:collapse ;                  
        }
        
        .tb th
        {
            border:1px solid black;
            padding:5px;
        }
        
        .tb td
        {
            border:1px solid black;
            padding:5px;
        }
        
    </style>
    <script src="js/jquery-1.10.2.min.js" type="text/javascript"></script>
    <script>
        $(function () {

            // test ser01
            $.getJSON("server02.ashx", function (data) {

                var vTable = $("<table class='tb' border='1'></table>");
                var vItem01 = "";

                //convert JSON string, not an object
                var data2 = $.parseJSON(data);

                //header
                vItem01 += "<tr><th>title</th><th>price</th><th>author</th></tr>";                               

                $.each(data2, function () { 
                    vItem01+="<tr>";
                    $.each(this,function(property, value){
                        vItem01+="<td>"+value+"</td>";
                    });
                    vItem01 += "</tr>";                    
                    
                });

                $(vTable).append(vItem01);
                $(".div01").append(vTable);

            });
        });
    </script>
</head>
<body>
    <form id="form1" runat="server">
    <div class="div01">
    </div>
    </form>
</body>
</html>


希望透過以上簡單範例,會讓你對於 jQuery 與 JSON 資料傳遞會有更親切的感覺。

2016年8月24日 星期三

透過 BlockUI 產生遮罩效果


當預期後端 Server 的處理時間會很久時,總是希望讓使用者知道系統還活著,只是正在處理中。這時,就會希望有個「遮罩」效果,讓背景呈現灰階、甚至放一個動態 .gif 圖檔來表示。

網路上蠻多推薦 BlockUI 的文章,自己實際去練習,發現還蠻容易上手的。

首先,必須先把會用到的 .js 抓回來。 (  jQuery, BlockUI )
然後在網頁上引用他們。


    <script src="Scripts/jquery-1.4.1.min.js" type="text/javascript"></script>
    <script src="Scripts/jquery.blockUI.js" type="text/javascript"></script>


而使用 BlockUI 的方法則是:
$.blockUI({ message: '<div>處理中! </div>' });  

不過,為了讓等待時不枯燥無聊,所以另外放了一個會動的 .gif 圖檔。可以到 ajaxload 去客製化自己喜歡的動態圖檔再下載使用。


完整程式如下:

Test.aspx

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title></title>
    <script src="Scripts/jquery-1.4.1.min.js" type="text/javascript"></script>
    <script src="Scripts/jquery.blockUI.js" type="text/javascript"></script>
    <style>
        .divAlert 
        {
            color:Red;
            font-size:18px;
            line-height:25px;            
            vertical-align:middle;
        }
    </style>
    <script>
        $(function () {
            $("input[id$=btn01]").click(function () {
                $.blockUI({ message: '<div class="divAlert">處理中! &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<img width="20px" src="./images/loader-red.gif"></img></div>' });  
            });

        });
    </script>
</head>
<body>
    <form id="form1" runat="server">
    <div>
    
        <asp:Button ID="btn01" runat="server" Text="點選" onclick="btn01_Click" />
    
       
        </div>
    </form>
</body>
</html>



Test.aspx.cs

using System.Threading;


protected void btn01_Click(object sender, EventArgs e)
{
    //讓程式跑久一點... 5 秒
    Thread.Sleep(5000);        
}

參考:
01:ajaxload
02:BlockUI Plugin - 功能完善的頁面、訊息遮罩
03:使用 jQuery 的blockUI 顯示 讀取中

2016年6月6日 星期一

只抓片段的 .load()

在 jQuery 中,可以透過 .load() 來抓取其他頁面的資料。

一般來說,我可能只會用到  $("#divContent").load("pageB.htm");

但最近發現,.load(url)  裡的 url ,除了可以填入網址外,也可以透過類似 jQuery 的 select 條件,對 url 的內容進行條件篩選。

舉例來說,$("#divContent").load("pageB.htm div");   ,就可以抓取 pageB.htm 的內容,同時過濾資料,只取有 div 的內容。

同樣的,$("#divContent").load("pageB.htm #myDiv"); ,則是只抓取 pageB.htm 裡 ID 為 myDiv 的內容。

假設 pageB.htm 的內容如下:

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title></title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
    AAAAA<br />
    BBBBB
    </div>
    <div id="myDiv">
    CCCCC
    </div>
    </form>
</body>
</html>

那 $("#divContent").load("pageB.htm #myDiv");  的結果,就只會出現 :CCCCC   了!

參考:
01..load()
02.loading page framents with Jquery AJAX

2015年10月26日 星期一

Angular 與 jQuery 的先後問題


近日在練習 Angular.js 的 ng-repeat 時,發現一個很怪的現象。程式碼如下:


<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" ng-app="NotesApp">
<head>
    <title></title>        
    <script src="//code.jquery.com/jquery-1.7.1.min.js"></script>
    <script src="js/angular.min.js" type="text/javascript"></script>    
 
</head>
<body  ng-controller="MainCtrl as ctrl">
    <table>
        <thead><tr><th>姓名</th></tr></thead>
        <tbody ng-repeat="note in ctrl.notes">
            <tr >
                <td>
                    <input type="text" id="txtName" value="{{note.UserName}}" ng-model="note.UserName" />
                </td>            
            </tr>
        </tbody>    
    </table>
    

    <script type="text/javascript">
        angular.module("NotesApp", [])
        .controller("MainCtrl", [function () {
            var self = this;
            self.notes = [
            { id: 1, UserName: 'Paladin' },
            { id: 2, UserName: 'Nikki' }
            ];

        } ]);
    </script>
</body>
</html>

理論上,畫面會根據 self.notes 的內容,於 <table> 裡面產生了兩筆資料。如畫面所示,的確也產生出兩筆資料。但有趣的是:
1.當我在 IE 瀏覽器使用中文輸入法輸入「中文」時,文字框的資料被清空了。
2.當我在 Chrome 瀏覽器使用中文輸入法輸入「中文」時,文字框的資料變成重複的「中文」。
3.當我在 FireFox 瀏覽器使用中文輸入法輸入「中文」時,文字框的資料是正常顯示。

就在我拜讀了 Angular 与 jQuery 加载顺序的问题 這篇文章後,發現,原來載入 jQuery.js 與 Angular.js 大有學問。當載入 Angular.js 後,Angular 會把 window.jQuery  擴展到自己的 jQLite。為了避免兩個 JS 出現相容性的問題,所以建議先載入 jQuery,再載入 Angular。

讀到這裡,似乎有摸到邊了,就算不完全懂,也似懂非懂。但猛然回頭,阿我不就是照他建議的順序在寫嗎,怎麼還是錯呢!於是,我很認命的去檢查 jQuery 的版本,透過一個版本一個版本去比對,終於找到端倪了。當 jQuery 版本引用到 1.9.0 以後,原先那奇怪的中文輸入問題就解決了。

最後,我在 Angular FAQ 的內容裡面看到一段話:

Does Angular use the jQuery library?

Yes, Angular can use jQuery if it's present in your app when the application is being
bootstrapped. If jQuery is not present in your script path, Angular falls back to its
own implementation of the subset of jQuery that we call jQLite.

Angular 1.3 only supports jQuery 2.1 or above. jQuery 1.7 and newer
might work correctly with Angular but we don't guarantee that.

也就是說,目前僅保證與 jQuery 的搭配是支援 jQuery 2.1 之後的版本。jQuery 1.7 或後面的新版本,則是不保證能正常執行。下次再遇到這種怪怪的問題時,不僅僅是引用的順序很重要,連版本也要注意了。雖然 Angular 建議我們稱這機會好好學 Angular 就好,不要再用 jQuery 這肥肥的程式了,但,這身上的包袱,可不是一時半刻就能抖乾淨的啊!

參考:
01:Angular 与 jQuery 加载顺序的问题
02:Angular FAQ

2015年10月21日 星期三

判斷瀏覽器是否有支援 required

在追查判斷瀏覽器是否有支援 Html5  required 功能時,看到網路上很多人都用了
if ($("<input />").prop("required") === undefined)
來判斷。我很好奇,$("<input />").prop("required"),這到底是什麼東西啊?

2015年4月7日 星期二

微妙的關係

jQuery 的選擇條件裡,存在著 child-selector 與 descendant-selector 的階層關係。

$("A > B") 表示著「父子關係」
在整個網頁的 DOM 裡找到所有的 B,再看 B的父親是不是 A,如果是,則保留;不是,則刪除,最後留下的就是我們所要的 B。

$("A    B") 表示著「子孫關係」
在整個網頁的 DOM 裡找到所有的 B,再用遞迴的方式去看看他的祖先是否有 A 存在,有的話就保留,沒有就剔除,最後留下的就是我們所要的 B。

由此可以看出,在「子孫關係」中,我們為了要能夠判斷祖先是否存在我們所指定的項目,所以需要透過遞迴的方式不斷地往上去尋找。而找尋的時間,就會隨著 DOM 階層的複雜而增加。

針對效能的考量,當已經知道可以透過「父子關係」就能找出想要的資料時,就該使用「父子關係」,而避免使用「子孫關係」。

參考:
01:Child Selector
02:Descendant Selector
03:網站開發新路線:jQuery核心詳解與實踐應用

2012年11月5日 星期一

一場誤會

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="jsTest.aspx.cs" Inherits="WebApplication1.jsTest" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title></title>
    <script src="http://code.jquery.com/jquery-1.6.4.min.js"></script>    
  
</head>
<body>
    <form id="form1" runat="server">
    <div>
昔誰持種來 而今佳色開<br>
昔誰持種來 而今佳色開<br>
昔誰持種來 而今佳色開<br>
    </div>

    <script>alert('提示訊息');</script>


    </form>
</body>
</html>

如上很簡單的 HTML 語法,只是好奇的想知道,是先跳出 javascript 的「提示訊息」呢,還是會先顯示「昔誰持種來 而今佳色開」的說明呢?我覺得在剖析 HTML 時,是由上而下的順序,應該會先顯示文字說明,而 javascript 是擺在最後面,所以會放到後面才執行。不只我這麼說,別人也是如是說,請看:「Load and execution sequence of a web page?」對於 mauris 所解釋的內容,真的非常詳細。

但我在 IE8 瀏覽結果時,卻出現如下結果:

而 chrome 與 firefox 則是如下(以 chrome 為例):

這說明了,以上面的範例來說,IE8 是先執行 javascript ,然後再對文字說明做處理;相反地,Chrome 與 FireFox 則是先對文字說明做處理,然後再執行 javascript。但這樣的結果,還真的讓人很疑惑?於是我再測了一下 IE6,沒想到 IE6 的行為,竟然跟 chrome 與 firefox 是一樣的,難道 IE8 是怪胎嗎?或許把過錯都推給 IE8 還蠻多人會覺得理所當然,但直到有一天,我把 jQuery 的版本升級到 1.7.1 之後,IE8 的處理結果竟也跟其他瀏覽器都一致了。原來事情的始末,竟是 jQuery 1.6.4 的版本,造成 IE8 在執行 javascript 時的觸發順序都提到最前面了。

在尚未發現主要原因是 jQuery 版本所引起之前,我的作法是在 javascript 標籤屬性裡加上 defer:

<script defer>alert('提示訊息');</script>

defer 這關鍵字,僅支援 IE 瀏覽器,他會讓 javascript 的執行時間延遲到整個頁面都下載完成後才執行。對我而言,只要跳出訊息視窗時不讓背景畫面一片空白,也就可以了。只是沒想到,真正引發問題的原因竟是自己所使用的 jQuery 版本。

IE8,我錯了,請您原諒~



參考:
01:Load and execution sequence of a web page?
02:姚博文 Script中defer的作用
03:asp.net弹出信息框——没有用ScriptManager
04:HTML <script> 标签的 defer 属性

2012年10月4日 星期四

colorbox 的右邊、下面都消失了

今天遇到一個很沒良心的問題,找到問題的癥結點後,反而沒有一種喜悅感,卻隱約有一股想要去撞牆的衝動。

我想要透過 colorbox 去完成一個開視窗的動作,但開的卻很不漂亮。如下圖所示,右邊的框、下面的框都不見了,檢查了程式,該有的都有了,不該有的也加了一堆,畫面就一直缺了一角,醜醜的。


最後看到「Colorbox的官方介绍和colorbox的常见问题中文翻译」提到,jQuery 和 colorbox.css 必須在 jquery.colorbox.js 之前引入。自己檢查了一下程式碼的順序,我竟然把 colorbox.css 擺在最下面。經過調整順序之後,真的恢復正常了。


這烏龍讓我想起一句話:「我們都沒有錯,只是在錯的時間遇上對的人」。

如果硬是要多寫一些話來描述,我覺得引用下面這段還蠻適合的:


當我倆敞開自己
你把自己給我, 我把自己給妳
當我們沉潛
妳進入我, 我進入妳
當我們消失
你消失在我裡面, 我消失在妳裡面
然後, 我是我
而妳是妳!

出處:為愛朗讀

在愛情的世界裡,錯誤的時間遇到對的人,往往不會有好的結局
在程式的世界了,錯誤的順序遇到colorbox,往往不會有好的畫面


參考:
01:Colorbox的官方介绍和colorbox的常见问题中文翻译
02:為愛朗讀

2012年7月6日 星期五

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



先前曾經在「透過 jQuery 取得 Asp.Net 裡 CheckBoxList 被勾選的文字」文章記錄了當時的解決方法,最近再次遇到同樣的問題,試著換另一種做法來處理。

CheckBoxList 在網頁上的原始碼如下:

<table id="cb" border="0">
<tr>
 <td><input id="cb_0" type="checkbox" name="cb$0" />
 <label for="cb_0">paladin</label>
 </td>
</tr><tr>
 <td><input id="cb_1" type="checkbox" name="cb$1" />
 <label for="cb_1">ltt</label>
 </td>
</tr><tr>
 <td><input id="cb_2" type="checkbox" name="cb$2" />
 <label for="cb_2">lee</label>
 </td>
</tr>
</table>


在上面程式可以發現,CheckBox 的內容,是由後面緊接著的 Label 來定義。這次透過 jQuery 所提供的 .next() 函數,去找到所挑選物件的下一個兄弟姊妹,剛好 Label 正是 CheckBox 的第一順位兄弟姊妹。換言之,只要利用:

$("#cb_0").next().text()

就可以得到第一個 CheckBox 的值 :「paladin」 了。而最初目的:透過 jQuery 取得 Asp.Net 裡 CheckBoxList 被勾選的文字,就可以改寫如下:

<script>
    function ShowData() {
        var str = "";
        $("input[type=checkbox]").filter(":checked").each(function () {
            str = str + $(this).next().text() + ',';
        });

        alert(str);
    }

    $(function () {

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

比較起來,這個寫法似乎比過去的簡潔許多。

但如果 CheckBoxList 的 RepeatLayout 屬性設為 Flow,這方法是否依然可行呢? RepeatLayout=Flow 的 HTML Code 如下:
<span id="cb_flow">
 <input id="cb_flow_0" type="checkbox" name="cb_flow$0" />
 <label for="cb_flow_0">paladin</label><br />
 <input id="cb_flow_1" type="checkbox" name="cb_flow$1" />
 <label for="cb_flow_1">ltt</label><br />
 <input id="cb_flow_2" type="checkbox" name="cb_flow$2" />
 <label for="cb_flow_2">lee</label>
</span>

CheckBox 後面的第一個兄弟姊妹,正是我們所要的值,所以這方法依然還是行的通。
參考:
01:透過 jQuery 取得 Asp.Net 裡 CheckBoxList 被勾選的文字
02:.next()

2012年7月5日 星期四

jQuery 的 :checked 在 Opera 不正常



在 jQuery 裡,如果想要知道 checkbox 有幾個被選取,可以使用

$("input:checked").size()

但我發現這方法,適用於 IE、Firefox、Chrome ,卻不適用 Opera 瀏覽器。我試著用一段測試程式如下:


<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title></title>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js" type="text/javascript"></script>
    <script>
        function DoCheck() {
            alert($("input:checked").size());            
        }
    </script>
</head>
<body>
    <form id="form1" runat="server">
    <input type="button" id="btn" value="check" onclick="DoCheck();" />
    <div>
    <input id="cb1" type="checkbox" name="cb"  />111 <br />
    <input id="cb2" type="checkbox" name="cb"  />222 <br />
    <input id="cb3" type="checkbox" name="cb"  />333 <br />
    </div>
    </form>
</body>
</html>

在 Opera 測試時,任意更改 checkbox 的選取組合,會發現 alert($("input:checked").size()); 所得到的結果,竟然會出錯,一開始還以為自己眼花,但沒想到是真的。在 jQuery 的 BUG TRACKER,可以看到目前已經有人提出同樣的問題了。

慶幸的,是目前還有一個各個瀏覽器都還支援的寫法:

$("input").filter(":checked").size()

所以,在 jQuery 尚未提出修正之前,還必須先以 .filter() 的方式來取代。

Opera 版本:11.62
jQuery 版本:1.7.2

2012年4月20日 星期五

hyperlink 可以 disabled 嗎?

記得以前在網頁上,如果想要把一個按鈕變成不可點擊,只需要將該按鈕的屬性設為  disabled  就可以了。只是現在我是有很多個超連結(hyperlink),也希望透過設定 disabled 就能把該超連結變成無效且不可點擊。

於是我試著寫出以下的測試程式:

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title></title>    
</head>
<body>
    <form id="form1" runat="server">
    <div>
    <a href="#" onclick="alert('A1');" >A1</a> <br />
    <a href="#" onclick="alert('A2');" >A2</a> <br />   
    <a href="#" onclick="alert('A3');" disabled="disabled" >A3</a>
    </div>

    <div>
    <input type="button" value="B1" onclick="alert('B1');" /> <br />
    <input type="button" value="B2" onclick="alert('B2');" /> <br />
    <input type="button" value="B3" onclick="alert('B3');" disabled="disabled" />
   
    </div>
    </form>
</body>
</html>

這似乎沒甚麼難的,只是... 當我開啟 firefox、chrome 等瀏覽器時,原先被設為 disabled 的超連結竟然還可以被點選,且觸發 onclick 事件。這種現象在 Button 身上並不會因瀏覽器不同而有所差異,目前只有超連結才會。

為了避免這不一致的運作行為,我參考了 Disable anchors in Chrome/WebKit/Safari 的作法,去判斷每一個超連結,如果屬性有設 disabled,就避免觸發 click 事件。

所以加上一段 jQuery Code 去處理所有 disabled 的超連結後,就可以適用於各瀏覽器了。


<script>
    $(function () {
        //避免 disabled 的 hyperlink 被觸發, chrome,firefox 需要這段處理
        $("a").click(function () {
            if ($(this).attr("disabled") == "disabled") {

                event.preventDefault();
            }

        });
    });
</script>
 
參考:
01: Disable anchors in Chrome/WebKit/Safari
02: jQuery .attr(“disabled”, “disabled”) not working in Chrome
03:.prop() vs .attr()

2012年3月7日 星期三

自動調整 iframe 高度


以前使用 iframe 時,總是無可避免當 iframe 裡的資料過長時,就得透過 scroll bar 來捲動,如果刻意將 iframe 的高度設很高,則又擔心有些時候會太浪費網頁版面,如果能夠讓 iframe 依據內容而調整高度,似乎是個比較有彈性的作法。


關於這個想法,在網路上找到兩種類似的作法。


一、Lost-In-Code
在這個網站,提供了一個方便你外掛的 javascript,jquery.autoheight.js。日後只需要將 iframe 的 class 設定為 『autoHeight』,就能夠自動調整 iframe 的高度了。雖然他取名為 jquery,但仔細去觀察 jquery.autoheight.js 這隻程式,裡面並沒有用到 jquery 的語法。作者雖然在他的網頁上註明要引用 jquery 函式庫,但我發現,不引用也是可以的。但實際操作上,自己有遇到一個問題,就是去點選瀏覽器右上方的「最大化/往下還原」時,因為不會重算父親的高度而因此破功。所以自己再加上 $(window).resize() 去重算就可以解決。也因為如此,我還是把 jquery 引用進去好了。


    <script src="Scripts/jquery-1.4.1.min.js" type="text/javascript"></script>
    <script src="Scripts/jquery.autoheight.js" type="text/javascript"></script>
    <script>
        $(function () {
            //攔 resize 事件,並呼叫 jquery.autoheight.js 的 doIframe() 方法
            $(window).resize(function () {               
                doIframe();                
            });
        });
    </script>

<body>
    <form id="form1" runat="server">
    <div>
    <div class="dean_ch">這是父親頁面</div>
    以下是 iframe <br />
    <iframe width="100%" src="FrameA.aspx"  scrolling="auto" frameborder="0"  class="autoHeight" id="ifA"></iframe>    
    </div>
    </form>
</body>

另外 『91』與 『梅問題』 也針對這方法做了介紹,可以參考。


二、Phine Solutions
這個方式適用於每個 iframe,自己去控制呼叫者(父親)所設定的高度。此外,為了處理「最大化/往下還原」的問題,也加上 $(window).resize() 的處理。

    <script src="Scripts/jquery-1.4.1.min.js" type="text/javascript"></script>
    <script>
        function DoAdjHeight() {
            var theFrame = $("iframe", parent.document.body);
            theFrame.each(function () {
                $(this).height($(document.body).height() + 35);
            });
        }
        $(function () {

            DoAdjHeight();

            $(window).resize(function () {
                DoAdjHeight();
            });


        });
    </script>



以上兩種方法,發現它們都會在程式裡面加上一個特別數字 35,似乎是一種最適切的高度位置吧!自己曾經刻意將瀏覽器的縮放比例任意變大變小,的確在有些情況,上述的兩種方式也會突然冒出 scroll bar ,但這種特殊的操作行為,或許可以當成例外,畢竟會這樣使用的人不多;但果真要去處理的話,可能就要去調整這特別的數字。目前,我將他設定為100,幾乎任何縮放比例都可以顯示正常。所以這地方,如果有需要時才去調整這參數會比較適當。

【測試程式下載 】
於測試程式中,TestA.aspx 是使用 Lost-In-Code 的方法,而 TestB.aspx 則是使用 Phine Solutions。



參考:
01:http://www.lost-in-code.com/programming/jquery-auto-iframe-height/ (lost-in-code)
02:http://www.dotblogs.com.tw/hatelove/archive/2010/08/12/javascript-iframe-autoheight.aspx (91)
03:http://www.phinesolutions.com/use-jquery-to-adjust-the-iframe-height.html (Phine Solutions)
04:http://www.minwt.com/?p=2425

2012年2月20日 星期一

讓 GridView 具有簡單又不失專業的 EmptyDataTemplate


使用 GridView 時,如果它的資料來源沒資料時,顯示個「找不到、0筆資料...」類的訊息,似乎可以讓使用者很清楚的區別。這個功能只需要在 <EmptyDataTemplate>做些訊息的設定即可。但如果是希望即使沒資料,也必須讓 GridView 的 Header 都顯示出來,或是有自訂的樣式時,那要怎麼處理呢?

我在 sidesofmarch 的「Cleaning up the GridView’s EmptyDataTemplate (damn those tables!)」發現了作者的怒吼,認為與其花很多時間在研究 <EmptyDataTemplate>,不如簡單地去判斷是否資料來源有資料,如果沒有,則隱藏目前的 GridView,再進一步去顯示自己所要顯示的資訊。

另外也比較了「ListView EmptyDataTemplate - how to use EmptyDataTemplate」這篇文章,透過 CSS 的定義去達成效果,似乎比較符合自己目前的期待,但如果能夠有更簡單一點的作法,會比較漂亮一些。

更仔細點觀察 GridView ,當我有設定 <EmptyDataTemplate> 且資料來源為 0 時,如果 GridView 原先有放了 4 個欄位,則 <EmptyDataTemplate> 會產生一段 HTML Code:

<tr class="Theader"><td colspan="4"></td></tr>

不管日後在  <EmptyDataTemplate> 放任何東西,都會放在 <td colspan="4"> 裡面,如此就會讓我原先已經套好視覺的 GrideView 顯得與既有的其它 GridView 看起來就會有點不一樣,有點怪,有點壞。

不過,我發現,如果在 <EmptyDataTemplate> 設定一個自訂的 <tr>:

<tr><th>上傳文件</th><th>上傳日期</th><th>說明</th><th>建檔人</th></tr>

,則所產生出來的 HTML,就會有兩個 <tr>,也就是:

<tr><td colspan="4"></td></tr>
<tr><th>上傳文件</th><th>上傳日期</th><th>說明</th><th>建檔人</th></tr>





這樣子的效果,除了第一個 <tr>會讓畫面很突兀外,基本上都已經滿足我的需求了。為了讓第一個 <tr>在畫面上消失,我試著使用 jQuery 把它隱藏起來。

在  <EmptyDataTemplate> 裡,我放入:
<tr class="tr_empty"><th>上傳文件</th><th>上傳日期</th><th>說明</th><th>建檔人</th></tr>


jQuery 則是:
<script>
    $(function () {

        $(".tr_empty").each(function () {

            $(this).parent().find("tr").first().hide();

        });

    });

</script>


這段 jQuery,是在頁面上搜尋所有有定義 class name 為 tr_empty 的物件,往上找到他的父親,<tbody>,再從 <tbody> 裡面往下搜尋第一個 <tr>,並將其隱藏。

這樣就可以將第一個 <tr>隱藏,只剩下我所要呈現的第二個 <tr>

參考:
01:Cleaning up the GridView’s EmptyDataTemplate (damn those tables!)
02:ListView EmptyDataTemplate - how to use EmptyDataTemplate

2012年2月17日 星期五

讓頁尾永遠放在下面

一般來說,網頁的頁首應該要擺最上面,頁尾要擺最下面,中間則是放些比較正經的內容。但如果某個頁面實在乏善可陳,就容易出現頁尾下方空出一大片空白的現象,如何把頁尾永遠放到最下面,真的只是「面子」問題,單純就是看得比較順眼就是了。


在「jQuery教學-重現DIV區塊高度100%的夢想」提到了 autoheight.js ,會透過 jQuery 去計算扣掉頁首、頁尾後需要擴展的內文高度,實際練習後發現非常簡單,真不愧為作者所號稱的懶人包。

使用時,記得將 jQuery 以及  autoheight.js 引用:


 
<script src="Scripts/jquery-1.6.4.min.js" type="text/javascript"></script>
<script src="Scripts/autoheight.js" type="text/javascript"></script>

在網頁的排版上,將頁首、內文、Footer 分別各放在一個 Div 裡,參考一下作者所提供的類別定義:


  • none="ture"->直接取得實際高度,排除所有CSS的設,如:border、margin、padding等。
  • _height="none"->扣除高度。
  • _height="auto"->高度100%
所以我的頁面上,大至會有以下安排:
   <div _height="none"> 頁首
   <div _height="auto"> 內文
   <div _height="none"> 頁尾

如此便可以簡單達成頁首、頁尾分別擺放在網頁的上面以及下面。

參考:梅問題:jQuery教學-重現DIV區塊高度100%的夢想

備份下載 :autoheight.js

2011年12月27日 星期二

使用 jQuery 清除畫面輸入的資料

自己在查詢頁面撰寫「清除」按鈕的 jQuery 程式,發現還是整理起來,日後還蠻有機會參考的。

Case 1:將 ASP.Net 的 DropDownList 跳到預設選項。

假設下拉選單 ddl_DeptList1 預設第一個選項的值是空字串,則可以用
$("select[id*=ddl_DeptList1]").val("");


Case 2:將 ASP.Net 的 DropDownList 內容清除。
假設下拉選單 ddl_DeptList2 已經有許多 option 資料,則可以用
 $("select[id*=ddl_DeptList2]").find("option").remove();


Case 3:將 ASP.Net 的 CheckBox 勾選取消。
假設核選方塊 cbStatus 已經有許多勾選資料,則可以用
$("input[name*=cbStatus]").each(function () { this.checked = false; });


Case 4:將 ASP.Net 的 Radio Button 勾選取消。
假設挑選方塊 rb_cust_type 已經有一筆挑選資料,則可以用
$("input[name*=rb_cust_type]").each(function () { this.checked = false; });


Case 5:將 ASP.Net 的 TextBox 內容清除。
假設輸入方塊 tbx_date_start 已經有使用者輸入的資料,則可以使用
$("input[id*=tbx_date_start]").val("");




2011年12月7日 星期三

如何讓 radio 亮起來

使用 Visual Studio 設計 Web Form 頁面時,當我使用了 RadioButtonList 控制項,且將該控制項的 Enable 屬性設為 false 時,一般都會得到一個很醜且灰濛濛的介面。


是否將 radio 裡面的文字刻意指定顏色給它,就可以有所改善呢?於是我簡單的加了 <font color="red"> 在裡面。
<asp:RadioButtonList ID="RadioButtonList1" runat="server" Enabled="False">
 <asp:ListItem Value="1"><font color="red">世界是平的</font></asp:ListItem>
 <asp:ListItem Value="2"><font color="red">體驗經濟時代</font></asp:ListItem>
 <asp:ListItem Value="3" Selected="True"><font color="red">太極拳道幾</font></asp:ListItem>
</asp:RadioButtonList>

實驗結果出爐,結果是:沒採工,一點反應都沒有。但有趣的是,以 chrome 、firefox 來開啟頁面,竟然是「有起色的(是紅的)」...


這點差異,倒是蠻有趣的。進一步去檢視網頁的原始碼可以發現:當我將 radiobuttonlist 的 enable 設為 false 後,它所產生出來的 html code,幾乎每個 html tag 都可以發現 disabled="disabled" 的影子。 甚至連 <input id="RadioButtonList1_0" type="radio" 的外面都還包了一個 <span disabled="disabled">。原來,只要是 html tag 裡面有定義 disabled="disabled",則該 tag 的顏色,就會變成灰色,不管是哪個瀏覽器都一樣會有這個效果。只不過,當 tag 裡面,還有另一個 tag 時怎麼辦?對於 chrome、firefox 來說,他們分的比較細,他們允許每一個 tag 都有各自的呈現方式,外層 tag 並不會影響內層的 tag,大腸包小腸,誰說這兩個腸一定都非香腸不可呢?這問題的處理上,IE 就顯得簡化許多,只要是外層有設定 false,內層不管你怎麼設,都一定是灰的。甚至你可以做一個實驗,只要你在你的網頁的一開始就放一個 <span disabled="disabled">,並把 </span> 放到網頁內文的最後面,模擬將所有的頁面內容,通通都包進這個 <span disabled="disabled">,檢視一下結果會發現,使用 IE 瀏覽器,全部的控制項都變成灰色了,彷彿都不能動了一樣。但可別被它蒙蔽了,裡面的輸入方塊、按鈕...,每一個都還是可以敲、可以按,只不過顏色是灰色的而已;這奇特現象,在 firefox、chrome 則是不會見到的。



<table id="RadioButtonList1" disabled="disabled" border="0">

<tr>

<td><span disabled="disabled"><input id="RadioButtonList1_0" type="radio" name="RadioButtonList1" value="1" disabled="disabled" /><label for="RadioButtonList1_0"><font color="red">世界是平的</font></label></span></td>

</tr>
<tr>

<td><span disabled="disabled"><input id="RadioButtonList1_1" type="radio" name="RadioButtonList1" value="2" disabled="disabled" /><label for="RadioButtonList1_1"><font color="red">體驗經濟時代</font></label></span></td>

</tr>
<tr>

<td><span disabled="disabled"><input id="RadioButtonList1_2" type="radio" name="RadioButtonList1" value="3" checked="checked" disabled="disabled" /><label for="RadioButtonList1_2"><font color="red">太極拳道幾</font></label></span></td>

</tr>

</table>

所以,依據上面的說法,在 IE 瀏覽器,只要 radio button 不被 <span disabled="disabled"> 包圍住,理論上也是可以擺脫灰色的命運。那就再次試試看...
<input type="radio" value="A" name="ra1" checked="checked" disabled="disabled"><font 

color="red">paldin </font>
<input type="radio" value="A" name="ra1" disabled="disabled"><font color="red">lttlab </font>




還果真如此,所以在 IE 瀏覽器上,其實也是可以讓 disabled 的 radio button 有不一樣的顏色,只是我使用 Visual Studio 的 RadioButtonList 控制項,會自動幫我加入許多並非我想要的 html tag,導致不管我怎麼調顏色,都無法上色。

說了這麼多,那在 IE 瀏覽器上,是否有機會更改那些 Enable 設為 false 的控制項呢?由於我功力還不夠深厚,目前無法回答這問題,但偷吃步倒是有一招。

為了避免 IE 處理 disabled 屬性與其他人不同調,於是我就在頁面的開發上,就不事先去定義 RadioButtonList 的 Enable 屬性,而且也不從後端去設定它,改由透過前端的 javascript 或 jQuery 來完成。

ex:  $("input[type=radio]").attr("disabled", "disabled");

如此,只要一行指令,就可以讓所有頁面上的 radio button 無法作用,又能保有光鮮亮麗的色彩。

2011年11月28日 星期一

讓 jQuery UI 的 DatePicker 多個 clear 按鈕

Keith Wood 寫了不錯的日曆挑選元件,同時也被 jQuery UI 收錄為官方版的挑日期方案。所以我們只要在 datepicker 頁面,就可以找到。然而,如果你細心的去比較 Keith Wood 的個人網站,會發現該作者目前所發表的日曆挑選元件,似乎在功能上,比 jQuery UI 所發佈的還要多。舉例來說,下面的日曆元件是來自於 Keith Wood 目前的版本 4.0.6


有沒有發現,他有一個 Clear 的鏈結,點下去,會將目前的日期輸入方塊上的資料清掉。很重要嗎?如果你的日期輸入方塊,有設定為 readOnly = true 時,這種需求的機會應該就會變高了。那 jQuery UI 的有提供嗎?
目前 jQuery UI 的版本是:1.8.16,很不巧的,沒有,他並沒有 clear 的功能。但如果你真心喜歡一個人的話,理應可以包容對方不足的地方。但前提是,要先努力過,努力甚麼呢?先給他去整形一下吧...


雖然 jQuery UI 目前的版本並沒有提供,但熱心的工程師,總是會想出些「成人之美」的方案。我在 http://bugs.jqueryui.com/ticket/3999 看到了很多人的抱怨,但也發現了一個有建設性的解法,雖然要多寫幾行程式,但能抓到老鼠的都算是好貓啦!




<script type="text/javascript">
$(function(){
    $(".pickdate").datepicker({
        changeMonth: true,
        changeYear: true,
        dateFormat: 'yy/mm/dd',            
        showButtonPanel: true

    });

    // hack to add clear button
    // 增加清除按鈕 -Start (Ref. http://bugs.jqueryui.com/ticket/3999)
    //wrap up the redraw function with our new shiz
    var dpFunc = $.datepicker._generateHTML; //record the original
    $.datepicker._generateHTML = function (inst) {
        var thishtml = $(dpFunc.call($.datepicker, inst)); //call the original

        thishtml = $('<div />').append(thishtml); //add a wrapper div for jQuery context

        //locate the button panel and add our button - with a custom css class.
        $('.ui-datepicker-buttonpane', thishtml).append(
 $('<button class="\
  ui-datepicker-clear ui-state-default ui-priority-primary ui-corner-all\
  "\>Clear</button>'
 ).click(function () {
     inst.input.attr('value', '');
     inst.input.datepicker('hide');
 })
);

        thishtml = thishtml.children(); //remove the wrapper div

        return thishtml; //assume okay to return a jQuery
    };

    // 增加清除按鈕 -End

  
  
});
</script>
如此折騰一番後,就可以多生出一個 Clear 按鈕了。

測試程式 [下載]

參考:
01:http://bugs.jqueryui.com/ticket/3999
02:Keith Wood,http://keith-wood.name/index.html

2011年9月16日 星期五

讓 GridView 的 checkbox 狀態於分頁後還能保留


當 GridView 為每一筆資料列擺上 checkbox 時,別以為這樣對 user 很貼心喔,其實是夢靨的開始。 因為聰明的 user 在換頁後很快就會發現,前一頁有勾選的資料,在換頁之後,勾選狀態就不見了。原本你期待的是讚美與鼓勵,一夕間就變成 bug 與缺失了。想到下班後還要繼續加班改程式,所言至此 ,就不禁潸然流下男兒淚了...

不過,寫程式的最高心法就是:Copy Right (Copy is right,拷貝是對的)。往好處想,至少下次再遇到同樣的問題時,就可以不用再這麼辛苦從無到有了。如此累積下去,幾年後,每個人肯定都會身懷絕技。於是將這次解決的方法寫下來,日後再遇到同樣問題,有時間的話可以再去進一步最佳化;如果沒時間,至少也不會開天窗。 

我參考了網路上的文章,針對這問題提出兩種解決的版本,一種是從後端(server side)來處理,另一種則是從前端(client side)來處理。兩者的差別,在於勾選後是否會觸發 postback。當然,個人是比較偏好 client side 來處理,主要是因為程式碼比較簡潔、程式執行比較快速。

 ------ server side -------
說明:
將已勾選資訊存放在 List<string> lcb ,並將它透過 viewstate 來包裝。在 gridview 的 RowDataBound 事件,針對每個 checkbox 去註冊 GetPostBackEventReference(),讓 checkbox 一被勾選就會觸發 postback,同時將唯一可識別的資訊當作 postback 的參數。並於 Page_Load 攔截所 有 postback 事件,判斷是否是 checkbox 所發出,如果是,就更新 List<string> lcb 與 gridview 上 checkbox 的勾選與否資訊。

 .aspx
        <asp:GridView ID="gv" runat="server" AutoGenerateColumns="False" 
            EnableModelValidation="True" AllowPaging="True" DataSourceID="dsData" 
            onrowdatabound="gv_RowDataBound" PageSize="5">
            <Columns>
                <asp:TemplateField>
                    <ItemTemplate>
                        <asp:CheckBox ID="cb" runat="server" />
                    </ItemTemplate>
                </asp:TemplateField>
                <asp:BoundField DataField="id" HeaderText="ID" />
                <asp:BoundField DataField="name" HeaderText="Name" />
            </Columns>
        </asp:GridView>
    </div>
.aspx.cs
    List<string> lcb = new List<string>();

    protected void Page_Load(object sender, EventArgs e)
    {
        if (!IsPostBack)
        {
            ViewState["cbList"] = lcb;
        }

    

        string strTarget = "" + Request.Form["__EVENTTARGET"];
        string strCtl = strTarget.Split('$')[strTarget.Split('$').Length - 1];
        string strArg = "" + Request.Form["__EVENTARGUMENT"];

  
        HandleEvent(strCtl, strArg);
    }
    protected void gv_RowDataBound(object sender, GridViewRowEventArgs e)
    {
        if (e.Row.RowType == DataControlRowType.DataRow)
        {
            lcb = (List<string>)ViewState["cbList"];
            CheckBox cb = (CheckBox)e.Row.FindControl("cb");           
            cb.Attributes["OnClick"] = this.ClientScript.GetPostBackEventReference(cb, 

DataBinder.Eval(e.Row.DataItem,"id").ToString());

            if (lcb.Find(x => x.Equals( DataBinder.Eval(e.Row.DataItem, "id").ToString

().Trim())) != null)
                cb.Checked = true;
            else
                cb.Checked = false;
        }
    }

    private void HandleEvent(string strCtl, string strArg)
    {
        switch (strCtl)
        {
            case "cb":
                UpdateCBList(strArg);
                break;
        }
    }

    private void UpdateCBList(string strArg)
    {
        lcb = (List<string>)ViewState["cbList"];
        if (lcb.Find(x => x.Equals(strArg)) == null)
        {
            //no match,insert
            lcb.Add(strArg);
    
        }
        else
        {   
            //match,remove
            lcb.Remove(strArg);
        }

        //final
        ViewState["cbList"] = lcb;
       
    }
------ client side -------
說明:
在 gridview 的 RowDataBound 事件,將每一個 checkbox 都加上 key 的屬性,裡面存放唯一且可識別的資訊。再透過 jQuery 為每個 checkbox 註冊勾選時都要觸發函式:UpdateHiddenValue()。在這函式裡,會判斷被觸發的 checkbox 的 key ,是否已存在於隱藏欄位 hValue (注意,必須將這隱藏欄位加上 runat="server",即使分頁後,依然可以保存 hValue 裡面的值),如果不存在,則將 key 值加入 hValue ,否則則從 hValue 裡面移除。最後,讓 DataGridView 裡的 checkbox 都隨時與 hValue 保持勾選與否的資訊同步。

 .aspx
<head runat="server">
    <title></title>
    <script src="http://code.jquery.com/jquery-latest.js"></script>
    <script>
        $(function () {
            //定義 checkbox 被點選時所要觸發的動作
            $("input[id$=cb]").click(function () { UpdateHiddenValue(this.key); });

            //將隱藏欄位 hValue 的值與 DataGridView 的 checkbox 作對應更新
            $("input[id$=cb]").each(function (i) {
                if ((',' + $("input[id*=hValue]").val()).indexOf(',' + $(this).attr('key') 

+ ',') > -1) {
                    //已存在,將 checkbox 打勾
                    this.checked = true;
                }
                else {
                    //不存在,將 checkbox 勾選取消
                    this.checked = false;
                }
            });
        });


        function UpdateHiddenValue(strInput) {
            if ((',' + $("input[id*=hValue]").val()).indexOf(',' + strInput + ',') > -

1) {
                //已存在,將輸入的值從隱藏欄位 hValue 移除
                var v = ',' + $("input[id*=hValue]").val();
                v = v.replace(',' + strInput + ',', ',');
                v = v.substr(1, v.length - 1);
                $("input[id*=hValue]").val(v);
            }
            else {
                //未存在,將輸入的值加入隱藏欄位 hValue 
                $("input[id*=hValue]").val($("input[id*=hValue]").val() + strInput+',');
            }          

        }
    </script>
</head>
<body>
    <form id="form1" runat="server">
        <asp:GridView ID="gv" runat="server" AutoGenerateColumns="False" 
            EnableModelValidation="True" AllowPaging="True" DataSourceID="dsData" 
            PageSize="5" onrowdatabound="gv_RowDataBound">
            <Columns>
                <asp:TemplateField>
                    <ItemTemplate>
                        <asp:CheckBox ID="cb" runat="server" />
                    </ItemTemplate>
                </asp:TemplateField>
                <asp:BoundField DataField="id" HeaderText="ID" />
                <asp:BoundField DataField="name" HeaderText="Name" />
            </Columns>
        </asp:GridView>
        <input type="hidden" id="hValue" runat="server" />
    <asp:XmlDataSource ID="dsData" runat="server" DataFile="~/data.xml">
    </asp:XmlDataSource>
    <div>
    
    </div>
    </form>
</body>
.aspx.cs
    protected void gv_RowDataBound(object sender, GridViewRowEventArgs e)
    {
        if (e.Row.RowType == DataControlRowType.DataRow)
        {
            CheckBox cb = (CheckBox)e.Row.FindControl("cb");           
            cb.InputAttributes["key"] = string.Format("{0}", DataBinder.Eval

(e.Row.DataItem, "id"));
        }

    }
參考:
01:利用ASP.NET的HIDDENFIELD記錄GRIDVIEW的CHECKBOX狀態,並且加入全選、取消全選、分頁保留CHECKBOX狀態,達到類似GMAIL的郵件清單功能
02:GridView 欄位 CheckBox 全選及取消全選
03:測試程式下載

2011年7月14日 星期四

至少要交一個女友

如過要設計個頁面,讓使用者填寫歷任女友姓名,且要判斷至少要填寫一個。這需求很像還蠻簡單的。可以一筆一筆去檢查輸入方塊,只要有值就算通過了。

雖然判斷式一行一行寫不是難事,但卻稍嫌累贅,所以花了些時間想瞭解 jQuery 是否可以處理的更漂亮。於是找到了一個可行的方法,並將他記錄下來!

<html>
<head>
<script src="http://code.jquery.com/jquery-latest.js"></script>
<script>
function CheckNeedOne()
{
   var msg='有值的共有:'+$(".data").filter(function(index){ if($(this).val()=='') return false; return true; }).size();
   if($(".data").filter(function(index){ if($(this).val()=='') return false; return true; }).size()==0)
   { 
 alert(msg+'\n至少要填一項!');
 return false;
   }

   alert(msg);
   return true;
}
</script>
</head>
<body>
<input type="text" id="tbx01" class="data"><br>
<input type="text" id="tbx02" class="data"><br>
<input type="text" id="tbx03" class="data"><br>
<input type="text" id="tbx04" class="data"><br>
<input type="text" id="tbx05" class="data"><br>
<input type="button" value="Send" onclick="return CheckNeedOne();">
</body>
</html>

執行結果:












主要是使用了 jQuery 所提供的 filter(function(index) ) 方法。原先的 $(".data"),讓我取得了5個輸入方塊,再透過 filter( ) 來過濾我所需要的資料。只是這次所要過濾的規則,希望是透過自己所定的規則,判斷輸入方塊是否有值,也就是待會要寫在 function(index) 裡的程式。

在 function(index) 裡,如果目前所檢查的輸入方塊有值,就回傳 true ,反之,則回傳 false。所以就寫成:

if($(this).val()=='') 
  return false; 

return true;

所以,符合 filter(function(index)) 的結果,都是有資料的輸入方塊,最後再透過 .size() 來取得符合的數目,用它來判斷是否大於0,如果沒有的話,就會跳出警告訊息。

$(".data").filter(function(index){ if($(this).val()=='') return false; return true; }).size()
 

希望自己下次再看到這填寫歷任女友的需求時,還會找到更簡潔的作法。