Java Script的世界一向隨便,非我族類的一套library反而是種嚴謹,而對習慣隨便寫Java Script的我,花了半天才找到解法。問題如下: HTML內文 <div class="demo_jui"> <table cellpadding="0" cellspacing="0" border="0" class="display" id="table_grid"> <thead> <tr> <th width="20%">編號</th> <th width="80%">群組</th> </tr> </thead> <tbody id="tableBody"> </tbody> </table> </div> |
使用jQuery的DataTables.js去修飾table_grid $(document).ready(function() { oTable = $('#table_grid').dataTable({ "bJQueryUI": true, "sPaginationType": "full_numbers", "bProcessing": true, "iDisplayLength": 5 } ); |
動態生成reocrd function buildTable(tableData) { var tableBody = $("#tableBody"); tableBody.html(""); //add the table rows $.each(tableData, function(i){ tableBody.append('<tr></tr>'); var tr = $('tr:last', tableBody); tr.append('<td>' + tableData[i].id + '</td>'); tr.append('<td>' + tableData[i].group + '</td>'); }); }; |
結果呢?資料正常顯示,但分頁、排序的功能完全無效,後來才知道,既然使用了DataTables.js,就要用它的function去動態生成,雖同屬jQuery,不能用純jQuery語法生成。改法如下: | var oTable; // 宣告為global變數 function buildTable(tableData) { oTable.fnClearTable(0); // 等同html("") $.each(tableData, function(i){ oTable.fnAddData([ // 動態新增record tableData[i].id, tableData[i].group ]); }); oTable.fnDraw(); // 重新繪製 }; |
那麼誰去call buildTable呢?是Ajax: | function querySubmit() { dataString = $("#myForm").serialize(); $.ajax({ url: '<c:out value="${ctx}"/>/query.do', type: 'POST', data: dataString, dataType: 'json', success: function(data, status){ buildTable(data); }, error: function(xhrInstance, status, xhrException) { alert("failure:" + status); } }); return true; } |
Jemmy 發表在 痞客邦 留言(0) 人氣(1,417)
jQuery真是夠了。可以在Google Chrome work的addClass竟無法在IE8和FireFox 3上Run。原因竟是each這個迴圈,結果我習慣用break跳出迴圈在Google Chrome沒事,結果在jQuery真正的跳出迴圈關鍵字是return。
Jemmy 發表在 痞客邦 留言(0) 人氣(155)
以前學Perl是羨慕其散漫不拘乃至天馬行空的語意邏輯,但始終我只是個Perl的入門者。jQuery也有這種傾向,先記錄我在SelectBoxes這個plugin遇到的怪事之二、三。 第一件,SelectBoxes似乎會cache,假設<select>是用addOption新增,順序是<option 1>、<option 2>、<option 3>,若是用jQuery的empty()或html('')清空,再用addOption新增<option 3>、<option 4>,結果<option 4>會出現在<option 1>的第一個位置,<option 3>在第三個位置,而<option 2>的位置卻是空著一列。若使用removeOption(/./)清空,則無此現象。 第二件,利用JSON作為addOption資料來源,如:addOption(json[i].ID, json[i].NAME)。清空後,再假設是這麼寫的:addOption(data[i].emp_id, data[i].emp_name),結果會是後一筆一直蓋掉前一筆,最終只顯示最後一筆。除非json object的屬性名稱和上次一模一樣才能正常顯示,估計也是cache的問題。 jQuery始終還有許多Syntax Sugar還不會用,然後笨笨的一個個踹。比方說我要取得<tr>下每個<td>內容: | var tr = ${'#table_id tr'}; tr.each(function() { var itemId = $(this).children('td:first').text(); // 取得第一欄<td>文字</td> var enableFlag = $(this).children('td:eq(4)').children('input').attr('checked'); //取得第五欄的<td><input type=”checkbox” value=”Y” /> }); |
Jemmy 發表在 痞客邦 留言(0) 人氣(130)
承襲前篇,欲將Popup Dialog裡的一個Select Box所有的值,以JSON方式回call父視窗的JavaScript function。但很奇怪的是,若JSON長得像這樣:
[{"username":"Foo","userid":2},{"username":"Bar","userid":1}] 回到父視窗用SelectBoxes.js的addOption加到SelectBox,userid是value,username是顯示。卻只能加到第二筆,Debug過程看到它是有加第一筆,但加第二筆時,第一筆被remove。反之,把JSON內容順序弄相反,卻能正常兩筆顯示。而Popup視窗裡用的是另一套plugin-multiselect達成>>、>、<、<<功能,但奇怪的是在move時,都會被排序過,最後判斷是Sort問題所造成,所以在Popup Windows的Java Script如下:
| function restore() { var a2r = $('select[name="account2role"]'); a2r.sortOptions(false); // SelectBoxes.js的function,設成不排序。 var data = '['; // 組成JSON a2r.find('option').each(function() { if (data.length > 1) data += ','; data += '{"username":"' + $(this).text() + '", "userid":' + $(this).val() + '}'; }); data += ']'; // 組成JSON完畢 if (window.dialogArguments != null) { window.dialogArguments.callback(data); // 回撥父視窗的Java Script function } window.opener = null; window.close(); }; |
而父視窗的callback作法如下:
| function reselectAccount(data) { var obj = JSON.parse(data); // 將字串轉成JSON物件 var selObj = $('select[name="accounts"]'); selObj.empty(); $.each(obj, function(i) { selObj.addOption( obj[i].userid, obj[i].username); }); }; |
Jemmy 發表在 痞客邦 留言(0) 人氣(231)
想在下拉選單初始化時,預設選擇一個Option,蠻簡單的:
$('#selectBoxID').val('Taiwan')。val帶的參數是<option>的value屬性,而非標籤裡的資料。 第二種情形是,想預設第一筆被選,而不會事先知道value。有兩種作法:
$('#selectBoxID').val($('#selectBoxID option:first')); $('#selectBoxID option:first').attr('selected', 'selected'); jQuery還有兩個plugin強化SelectBox。一個可以把SelectBox當作DOM方式操作,如下: // import jquery.selectboxes.min.js $('#selectBoxID').empty(); // clear option $.each(data, function(i) { // data is a JSON $('#selectBoxID').addOption( // add a option data[i].id, // option value data[i].itemname); // option display }); |
另一個plugin是很常用的,兩個Select Box彼此Move的動作。通常有>>、>、<、<<的按鈕,片段如下:
// import jquery.multiselects-0.3.pack、jquery.multiselects-0.3.js $(function() { // (OPTIONAL) adjust the width of the select box to the bigger of the two $("select[name='available']").selectAdjustWidth("select[name='selected']"); $("select[name='available']").multiSelect("select[name='selected']", { trigger: "input[name='remove']", triggerAll: "input[name='removeAll']" }); $("select[name='selected']").multiSelect("select[name='available']", { trigger: "input[name='add']", triggerAll: "input[name='addAll']" }); }); |
感謝一位建教生慧潔幫忙做這樣的效果,下圖左的Select Box名為available,圖右名為selected,對照上面程式碼很容易懂。

Jemmy 發表在 痞客邦 留言(0) 人氣(608)
Struts1的Tag library轉成html,只有name,沒有id,因此jQuery很難用id selector去過篩。比如想在<html:text>標籤加個日曆小工具,得用name selector去篩選,在JSP設置jQuery的DatePicker的plugin如下:
| <script type="text/javascript" src="js/jquery/date.js"></script> <script type="text/javascript" src="js/jquery/jquery.datePicker.js"></script> <script type="text/javascript"> $(function() { Date.format = 'yyyy-mm-dd'; $('td input[name$="_date"]').datePicker({startDate:'1996-01-01'}); }); </script> |
影響所及,便是<td>後的,name屬性是以_date後綴的<input>標籤皆被附上DatePicker這個日曆小工具。只是還有個缺點就是萬一是java.util.Date型態,那麼初次顯示是連時分秒都顯示,可以在form load時再用jQuery把時分秒點掉:
| $('td input[name$="_date"]').each(function() { if ($(this).val().length > 10) { $(this).attr('value', $(this).val().substring(0, 10)); } }); |
form load即上述$(function() {…form load內容…});
Jemmy 發表在 痞客邦 留言(0) 人氣(235)
Struts1和jQuery越深研,學越多,狀況越多。最意外的是還有瀏覽器不相容的問題,原本在Google Chrome下可work的,到IE和FireFox便出錯,而且錯得都不一樣,馬的。IE問題出在CSS的問題,果如Java Script的大老道格拉斯在OSDC 2010說:IE 6 MUST DIE。我看IE8也…。 先列出解出和FireFox的問題。原來出在Struts的RequestProcessor的類別,我在JSP使用jQuery的$.ajax去做post,其url設定為/query.do,在Google Chrome裡,印出的Log是這樣:[RequestProcessor.java:161] : Processing a 'POST' for path '/query'。 而在FireFox的Log卻是:[RequestProcessor.java:681] : Invalid path was requested /jsp/permission/query。也就是在FireFox下,url事先加了目前的jsp的base path。目前只尋得治標方式。就是在struts_config.xml裡,除了設定/query的action之外,也設定/jsp/permission/query的action,而對映的Spring Bean也得追加相應的method,內容和@Bean(name="/query")一樣,只是變成@Bean(name="/jsp/permission/query"),而method name也要取不同名。希望下次找到治本方式,這個治標方式至少不必在前端程式加一堆瀏覽器的判斷。
2010/4/28:治本方式是設好Context定位給其它url使用。先在common.jsp設置如下,給其它jsp去include:
| <%@ taglib uri="/WEB-INF/tld/jstl/c.tld" prefix="c" %> <c:set var="ctx" value="${pageContext.request.contextPath}"/> |
之後用到Ajax或是submit的URL,一律前綴此標籤:
| $(function(){ $("#query").click(function() { dataString = $("#myForm").serialize(); $.ajax({ url: '<c:out value="${ctx}"/>/query.do', type: 'POST', data: dataString, dataType: 'json', success: function(data, status){ buildTable(data); }, error: function(xhrInstance, status, xhrException) { alert("failure:" + status); } }); return false; }); }); |
| $("#myForm").attr("action", '<c:out value="${ctx}"/>/query.do'); $("#myForm").submit(); |
據Google結果,原因是FireFox 3.x版禁止cross domain存取,是故才會有/jsp/permission/query的url出現。本想用<html:base>在Client解決,但還是失敗。 接著再把link的css和引入的Java Script檔,其路徑都用這種方式前綴,終於能並用於IE8、FireFox3和Chrome 4。
Jemmy 發表在 痞客邦 留言(0) 人氣(995)
DataTables.js是jQuery plugin裡較方便、設定較少的分頁表格功能。Google結果大多只有DataTables.js內容轉成JSON的飯粒,反過來較少,也是筆者在前端不熟稔所致,踹了快一週才找到方法,而且歷經SiteMesh和出現中文亂碼的問題。 先說為何選用JSON作為資料傳遞格式,JSON和XML一樣皆屬通用型格式,同樣意涵的資料在JSON裡表達可能占的空間更少。利用通用型格式可以讓前端與Web Server之間更鬆耦合,前端可以是JSF、Flex…,後端可以是Struts、Spring MVC甚至是.Net平台。 在Servlet端,透過
JSONArray.fromObject回傳json資料給前端,而前端的實作在Google時有一點實在很煩,就是落落長的程式碼,所以下面的實作分開講,希望能比較清楚的表達:
| <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <html:base/> <link href="styles/demo_page.css" rel="stylesheet" type="text/css" /> <!-- include相關css和js --> <link href="styles/demo_table_jui.css" rel="stylesheet" type="text/css" /> <link href="styles/jquery-ui-1.7.2.custom.css" rel="stylesheet" type="text/css" /> <script type="text/javascript" language="javascript" src="js/jquery/jquery.js"></script> <script type="text/javascript" language="javascript" src="js/jquery/jquery.dataTables.js"></script> <script type="text/javascript"> function buildTable(tableData) { <!-- 處理JSON的function --> var tableBody = $("#tableBody"); <!-- tableBody是<tbody>標籤ID,為dataTables.js所用 --> tableBody.html(""); <!-- 將<tbody>標籤內所有內容含標籤都清空 --> //add the table rows $.each(tableData, function(i){ <!-- JSON處理迴圈,匿名function的參數i是取得JSON的{} --> tableBody.append('<tr></tr>'); <!-- <tbody>後新增一個<tr>標籤空間 --> var tr = $('tr:last', tableBody); <!-- 在<tbody>取得最後一個<tr> --> tr.append('<td><input name="" type="checkbox" value="" /></td>'); <!-- <tr>後新增<td> --> tr.append('<td>' + tableData[i].id + '</td>'); tr.append('<td>' + tableData[i].username + '</td>'); tr.append('<td>' + tableData[i].name_tw + '</td>'); tr.append('<td>' + tableData[i].name_en + '</td>'); tr.append('<td>' + tableData[i].enable_flag + '</td>'); }); }; $(function(){ <!-- jQuery的Ajax處理程式 --> $("#query").click(function() { <!-- 為button的id query的onclick事件bind一個function --> dataString = $("#mainForm").serialize(); <!-- 將form data全序列化到一個變數,jQuery特有 --> $.ajax({ <!-- Ajax主程式 --> url: 'query.do', <!-- 指定action的url,如無,預設取得form的action屬性 --> type: 'POST', <!-- 指定form method,如無,預設取得form的method屬性 --> data: dataString, <!—form input --> dataType: 'json', <!-- 指定回傳type,包括html,text,xml,script等 --> success: function(data, status){ <!-- 回傳成功的動作,status是HTTP status --> buildTable(data); <!-- 呼叫上面的function --> }, error: function(xhrInstance, status, xhrException) { <!-- 回傳失敗的處理function --> alert("failure:" + status); } }); return false; }); }); $(document).ready(function() { <!-- 頁面DOM載入完畢後的匿名function --> oTable = $('#table_grid').dataTable({ <!-- table_grid為<table>標籤ID,指定被dataTable作用 --> "bJQueryUI": true, <!-- 可套用jQuery UI, 這部份再研究 --> "sPaginationType": "full_numbers" <!-- 分頁功能設定全有,two_button則只有上下頁兩個 --> }); } ); </script> <title>Demo</title> </head> |
對應的HTML部份內容如下:
| <div class="demo_jui"> <table cellpadding="0" cellspacing="0" border="0" class="display" id="table_grid"> <thead> <tr> <th width="7%"> </th> <th width="13%">ID</th> <th width="21%">登入帳號</th> <th width="19%">中文姓名</th> <th width="18%">英文姓名</th> <th width="22%">啟動旗標</th> </tr> </thead> <tbody id="tableBody"> </tbody> </table> </div> |
有別一般<table>下只有<tr>,DataTables.js在這兩者之間加了<thead>和<tbody>以區隔標頭和資料作用,所以才能夠在標頭上設置sort等功能。是故在第一個JavaScript片段,jQuery透過("#table_grid")找到id為table_grid的<table>標籤,再經由dataTable給它可分頁的功能,其它ID亦是如此。
Jemmy 發表在 痞客邦 留言(0) 人氣(1,649)
一流+一流=二流。一個優秀的元件可以獨當一面,甚至包山包海,當再遇到另一個優秀的元件,雖然獨當的一面不同,但週邊的能力可能踩到對方的地盤了,這是我花兩天才找出原因的。 jQuery使用Ajax向Server端取得JSON格式,卻老是出錯:
| $(function(){ $("#buttonID").click(function() { dataString = $("#formID").serialize(); $.ajax({ url: 'query.do', type: 'POST', data: dataString, dataType: 'json', success: function(data, status){ alert("succ:" + status); }, error: function(xhrInstance, status, xhrException) { alert("failure:" + status); } }); return false; }); }); |
最後將dataType改為text看傳回什麼,原來竟是踩到了SiteMesh的地盤了。SiteMesh是用Decorator模式為頁面做佈局管理員,PG只需專注自己頁面的開發,response後由SiteMesh打點header、footer、bar、Local的Menu Tree即可。是這個ajax接到的,並不是url(query.do)的回傳JSON,而是SiteMesh的佈局頁面,main.jsp,見下方的decorators.xml的粗體字部份。
| <?xml version="1.0" encoding="ISO-8859-1"?> <decorators defaultdir="/_decorators"> <!-- Any urls that are excluded will never be decorated by Sitemesh --> <excludes> <pattern>/nodecorate/*</pattern> <pattern>/styles/*</pattern> <pattern>/css/*</pattern> <pattern>/scripts/*</pattern> <pattern>/images/*</pattern> <pattern>/dojo/*</pattern> <pattern>/struts/*</pattern> <pattern>/commons/*</pattern> <pattern>/js/*</pattern> <pattern>/js/jquery/*</pattern> <pattern>/js/jquery/css/*</pattern> <pattern>/js/jquery/images*</pattern> <pattern>/login.jsp</pattern> <pattern>/timeout.html</pattern> <pattern>/j_spring_security*</pattern> <pattern>/query.do</pattern> </excludes> <decorator name="main" page="main.jsp"> <pattern>/*</pattern> </decorator> <decorator name="panel" page="panelDecorator.jsp"/> </decorators> |
解法就顯而易見,在<excludes>標籤新增一個<pattern>排除於SiteMesh的裝飾之外,即上述片段程式的紅字部份。 並附上在Struts的Action如何把內容轉成JSON傳回程式片段:
| JSONArray json = JSONArray.fromObject(list); PrintWriter out=response.getWriter(); out.println(json); out.flush(); return null; |
list變數內含JavaBean物件,而要記得return null,不是return mapping.findForward("success");。
Jemmy 發表在 痞客邦 留言(0) 人氣(451)
jQuery的"$('.test :hidden')與"$('.test:hidden')之間差異做了幾次才明白。 以空白隔開的叫做後代選擇器(Descendant Selectors),以下的"$('.test :hidden').length值為4,先找出class為test的,再其下的子元素俱:hidden的性質: <div class="test">
<div style="display:none;">aa</div> <!-- 1 -->
<div style="display:none;">bb</div> <!-- 2 -->
<div style="display:none;">cc</div> <!-- 3 -->
<div class="test" style="display:none;">dd</div> <!-- 4 這裡test沒什麼關係,它沒子元素-->
</div>
<div class="test" style="display:none;">ee</div>
<div class="test" style="display:none;">ff</div> 而$('.test:hidden')則是找出class為test同時俱:hidden性質的標籤,是故其length值為3:<div class="test">
<div style="display:none;">aa</div>
<div style="display:none;">bb</div>
<div style="display:none;">cc</div>
<div class="test" style="display:none;">dd</div> <!-- 1 -->
</div>
<div class="test" style="display:none;">ee</div> <!-- 2 -->
<div class="test" style="display:none;">ff</div> <!-- 3 -->
Jemmy 發表在 痞客邦 留言(0) 人氣(69)