[ASP.NET & jQuery]tr(支援table、GridView與ListView)點選後highlight
前言
其實之前一直有類似的需求,就是GridView要能支援當click某一列的時候,該列要highlight,
點別列的時候,換別列highlight。
說穿了,就是table裡點選了某一筆tr,要套上highlight的css,點別列時要把原本那列CSS還原。
更簡單的作法,就是每次都先把highlight的css移除,再針對這次點的tr套上highlight。
如果需求只有這樣,css就可以搞定了。
然而使用jQuery,我們可以更輕鬆的處理網頁上的DOM。
Problem
問題來了,ASP.NET Webform裡的postback,沒錯!又是它…
因為每次postback都會重新Render,
要怎麼把這次client端的動作記起來?
又得用hidden來偷記東西了…
由於希望team member可以不用到處copy & paste,以前的作法都是直接做一個custom control繼承listview或gridview,
在物件本身把這件事做掉…
然而這次希望使用ASP.NET原生控制項…
所以我又得傷腦筋一下,怎麼樣可以做的更漂亮。
Solution
目前只是先生一版堪用的solution來使用,未來希望可以連hidden都動態產生,讓PGR使用時更加無感。
原本設計邏輯:
- 符合條件的table,裡面的tr,click的時候,先將此table裡所有tr的highlight class remove掉,接著再將click的這個tr加上highlight class
- click的同時,將click的這個tr的id,記到hidden裡面
- 每次符合條件的tr ready後,將hidden的那筆tr套上highlight class
結果,因為我這邊使用的是ListView,在LayoutTemplate裡面放個table。
但在ListView的Template裡面的Control,server端得用findcontrol才能定位,這樣太麻煩了…
所以,就不如直接搜尋ListView裡面的tr好了…
但是天不從人願,ListView Render出來後,是沒有一個DOM的id跟ListView的clientID一樣。
舉例來說:
<asp:ListView ID="lvSpec" runat="server" >裡
<table id="spec" runat="server" class="grid" cellpadding="0" cellspacing="0">
再套上MasterPage後,table的html ID是長的像這樣:
『ctl00_ContentPlaceHolder1_lvSpec_spec』
所以,我想要拿ListView.ClientID來當作jQuery Selector的容器和條件,就宣告失敗了。
後來決定使用div跟class,當在這個div裡面的table,所有tr就會被套上我們的邏輯。
為了方便team member開發上更加server化,
我這邊的範例就使用Panel來代替div,並且將那一堆javascript,透過BasePage的method,動態的註冊與使用。
Play it
BasePage的Method:
/// ListView或table外,需要有一個panel包覆,在此panel內的tr被選取後,會套上"selected"的class,且將此tr的id塞到hidden裡
/// postback後則讀取hidden的值,將該tr加上"selected"的class
/// </summary>
/// <param name="panel">The panel.</param>
/// <param name="hidden">The hidden.</param>
public void ListViewHiddenMapping(Panel panel, HiddenField hidden)
{
string CoverSelectedRowJS = @"
function CoverSelectedRow(listViewID, hiddenID) {
$('#' + listViewID + ' tr').ready(function() {
var id = $('#' + hiddenID)[0].value;
if (id != """") { $('#' + id).addClass(""selected""); }
});
}";
string gridCoverBackSelectedJS = @"
$(document).ready(function() {
$('#" + panel.ClientID + @" tr').click(function() {
$(this).parents(""table"").find(""tr"").removeClass(""selected"");
$(this).toggleClass(""selected"", this.clicked);
$('#" + hidden.ClientID+ @"')[0].value = $(this)[0].id;
});
})";
gridCoverBackSelectedJS = gridCoverBackSelectedJS+@"
CoverSelectedRow('" + panel.ClientID + "', '" + hidden.ClientID + "');";
if (ExistSM())
{
ScriptManager.RegisterClientScriptBlock(this.Page, this.Page.GetType(), panel.ID, gridCoverBackSelectedJS, true);
ScriptManager.RegisterClientScriptBlock(this.Page, this.Page.GetType(), "CoverSelectedRowJS", CoverSelectedRowJS, true);
}
else
{
Page.ClientScript.RegisterClientScriptBlock(Page.GetType(), panel.ID, gridCoverBackSelectedJS);
Page.ClientScript.RegisterClientScriptBlock(Page.GetType(), "CoverSelectedRowJS", CoverSelectedRowJS);
}
}
/// <summary>
/// 檢查頁面上是否存在ScriptManager
/// </summary>
/// <returns></returns>
private bool ExistSM()
{
return (ScriptManager.GetCurrent(this.Page) != null);
}
aspx上,要有三個東西才能達到我們需要的效果:
- <asp:Panel ID="divSpec" runat="server" CssClass="datatable">
- <asp:ListView>或<asp:GridView>或<asp:Table>或<table>
- <asp:HiddenField ID="HiddenField1" runat="server">
Panel要包住table,Panel的class設定為datatable。
接著要在code-behind使用BasePage的method:
沒了,就這樣一行,搞定。
畫面:
註:
如果切換頁要清除highlight,請自行在切換頁的事件,將hidden.value清空即可。
換句話說,如果切到別頁,再切回來如果還要留著highlight,
就在tr ready的function裡面,額外加上頁碼的判斷,當id跟頁碼符合條件時,才套上highlight的class。
如果啥都沒做,那就是現在選第二筆,切到第二頁,第二筆還保留著highlight。
結論
相信在很多大師眼中,這篇文章這個範例是相當可笑的,
因為用了jQuery,要處理postback花的功夫,真的沒啥意義…
不過沒法子,需求就是這樣,就當作練習,也希望對大家有幫助。
blog 與課程更新內容,請前往新站位置:http://tdd.best/