jQuery:: Sort table
สวัสดีอีกครั้งหลังจากเจ็บตัวไปกับบอลโลกกินปลาหมึกย่างกันเป็นอาทิตย์ แหม... มันช่างแม่นเสียจริงๆ ทำเอาหลายๆ คนเซ็งกันเลย ดีนะที่ทายเฉพาะเยอรมัน ถ้าทายทุกๆ คู่แล้วถูกหมด สงสัยเจ้าพอลคงอยู่ในโลกนี้ไม่ได้แน่ๆ เลย (โดนจับกินซะก่อน)
นอกเรื่องกันแหละ แต่ช่วงนี้พุงออกเพราะปลาหมึกจริงๆ นะ... ผมคิดว่าหลายๆ ท่านที่เขียนเว๊ปคงเคยได้เขียนรายงานแสดงอะไรสักอย่างที่ต้องใช้ตารางแน่ๆ แล้วทีนี้ถ้าต้องการให้ค่าในตารางเรียงจากมากไปน้อย หรือน้อยไปมากละ จะทำยังไง ถ้าหากเราเชื่อมต่อกับฐานข้อมูลเราก็แค่เปลี่ยนคำสั่ง sql ซะ เท่านี้ข้อมูลก็เรียงกันใหม่แล้วแต่... ผมรู้สึกว่ามันไม่โปรเท่าไหร่ แถมมีการ refresh เกิดขึ้นด้วย นั่นมันไม่ใช้ concept ของ web2.0 นี่นา แล้วเราจะเขียนมันได้ยังไงล่ะ?
Javascript คือคำตอบ แต่มันยากนะ เขียนก็ยาก แถม debug ยังยากกว่าอีก Javascript Framework คือคำตอบ ในปัจจุบันมีหลายเจ้าเลยแถมแข่งกันอย่างสนุกสนานเสียด้วย ประสิทธิภาพก็ไม่แพ้กัน ที่นิยมบ้านเราก็มีหลายตัว แต่ที่น่าจะเยอะหน่อยก็คือ jQuery รองมาก็น่าจะเป็น Prototype (เขียนคู่กับ Ruby เป็นกิ่งทองใบหยกเลยแหละ) เมื่อก่อนผมก็เขียน Prototype แต่มีช่วงหนึ่งที่มันเริ่มไม่พอ แถมตัวยังใหญ่และเข้าถึง element class ไม่ได้ด้วย เลยต้องเปลี่ยนมาเป็น jQuery แทนใช้เวลาปรับตัวไม่นานก็ได้แหละครับ
แนวคิดเป็นยังไง?
ไม่ยากเลย ถ้าใช้ table ใน html มันก็เหมือน excel คือมี แถว (row) และคอลั่ม (col) ลองดูรูปประกอบละกันครับ
จากรูปในแต่ละคอลั่มเราจะทำการแยกส่วนที่เป็นข้อมูล (TD) และส่วนของหัวข้อ (TH) ออกจากกันโดยใช้ ขั้นตอนแรกให้เราสร้างตารางตามโค๊ดนี้เลยครับ
- <table width='50%' cellspacing='0' cellpadding='0' border='1'>
- <th>ลำดับที่</th>
- <th>ภาษา</th>
- <th>เงินเดือน</th>
- </tr>
- </thead>
- <td>1</td>
- <td>PHP</td>
- <td>25000</td>
- </tr>
- <td>2</td>
- <td>JAVA</td>
- <td>35000</td>
- </tr>
- <td>3</td>
- <td>Python</td>
- <td>30000</td>
- </tr>
- <td>4</td>
- <td>dot Net</td>
- <td>22000</td>
- </tr>
- <td>5</td>
- <td>Objective C</td>
- <td>50000</td>
- </tr>
- </tbody>
- </table>
แนวคิดง่ายๆ เลยครับ พอกดที่ TH ก็ให้ทำการอ่าน TD ที่อยู่ในแนวเดียวกันทั้งหมด (Column) คิดอาจจะง่ายแต่ลองเขียนแล้วยากเหมือนกัน (เหอะๆ) เขียนไปเขียนมาก็ได้โค๊ด jQuery แบบนี้ (อ่านจาก comment ล่ะกันครับ)
การเรียง ผมจะแยกการเรียงเป็นสองแบบคือข้อมูลที่เป็นตัวอักษร กับ ข้อมูลที่เป็นตัวเลข เพราะถ้าเรียงตัวเลขโดยใช้การเรียงแบบเดียวกับตัวอักษร มันจะเรียงได้ไม่ถูก
- $(document).ready(function(){
- $('table.sort-table').each(function(){
- var table = $(this); // เก็บตารางไว้ในตัวแปร table จะได้อ้างถึงได้ง่ายๆ
- $('th', table).each(function(column) { // เลือกหัว (th) ของแต่ละแถว
- var header = $(this); // เก็บ th ไว้ในตัวแปรจะได้อ้างง่ายๆ
- var sortKey = false; // ตัวแปรบอกว่า แถวนี้เรียงได้หรือไม่
- if(header.is('.sort-text')) { // เรียงคอลั่มแบบตัวอักษร
- sortKey = function(cell) {
- return cell.find('.sort-text').text().toUpperCase() + ' ' + cell.text().toUpperCase();
- // ทำการส่งข้อมูลในแต่ละช่องไปในตัวแปร sortKey
- };
- }
- else if(header.is('.sort-number')) { // เรียงคอลั่มแบบตัวเลข
- sortKey = function(cell) {
- var temp = cell.text();
- temp = parseFloat(temp);
- return isNaN(temp)? 0 : temp;
- // ทำการเลือกแต่ละช่องโดยตรวจสอบก่อนว่าเป็นตัวเลขหรือไม่ ถ้าไม่เป็นให้เปลี่ยนค่าเป็น 0
- };
- }
- if(sortKey) { // ถ้าตัวแปร sortKey มีค่าใส่เข้าไป
- header.click(function(){ // เมื่อคลิกที่ th ของแต่ละช่อง
- var sortDirection = 1; // 1 = น้อยไปมาก -1 = มากไปน้อย
- if(header.is('.sorted-asc')) { // class .sorted-asc เป็นตัวบอกว่าเรียงจากน้อยไปมากอยู่
- sortDirection = -1;
- }
- var rows = table.find('tbody > tr').get(); // เอาค่าทุกแถวที่อยู่ใน tbody ออกมา
- $.each(rows, function(index, row){ // ทำการเรียง
- var cell = $(row).children('td').eq(column);
- row.sortKey = sortKey(cell);
- });
- rows.sort(function(a, b) { // บอกทิศทางการเรียง
- if(a.sortKey < b.sortKey) return -sortDirection;
- if(a.sortKey > b.sortKey) return sortDirection;
- });
- $.each(rows, function(index, row){ // สลับแถวในตาราง
- table.children('tbody').append(row);
- row.sortKey = null;
- });
- // ด้านล่างแค่บอกว่าเรียงไปทางไหนแล้วเฉยๆ
- table.find('th').removeClass('sorted-asc').removeClass('sort-desc');
- if(sortDirection == 1) {
- header.addClass('sorted-asc');
- }
- else {
- header.addClass('sorted-desc');
- }
- table.find('th').removeClass('sorted').filter(':nth-child(' + (column+1) +')').addClass('sorted');
- });
- }
- });
- });
- });
เขียนไป comment ไป หลังๆ เริ่มขี้เกียจเลยออกมาได้ครึ่งๆ กลางๆ แบบนี้นะก็ลองดูแลลัพธ์กันก่อนได้จากตรงนี้เลย (คลิกที่ช่องแรกของแต่ละแถวเพื่อเรียงข้อมูลนะครับ)
เห็นไหมครับ ไม่ยากเลยใช่ไหม ก่อนเอาไปใช้งานก็อย่าลืมใส่ class ให้ table ของเราด้วยนะครับ ไม่อย่างนั้นมันไม่รู้จะเรียงตารางไหนแล้วเรียงฟิลด์ไหนด้วย ก็หวังว่าโค๊ดสั่นๆ ง่ายๆ นี้จะมีประโยชน์กับเพื่อนๆ นะครับ
ปล. เขียนอยู่สามวัน อ่านๆ ดูเหมือนมันไม่ค่อยต่อเนื่องเท่าไหร่เนอะ แต่ก็เอาเหอะเผาจนเสร็จแล้วแหละ


