[jQuery] jQuery DataTables 資料行加入checkbox、按鈕,關閉資料行排序、改變下拉選單的每頁顯示幾筆、變更DataTables樣式…等功能 Part5 final

 jQuery DataTables column add button checkbox

前言

本篇是jQuery DataTables系列文的最後一篇

最後一篇把之前沒提到,剩餘零散的功能統一集中在此說明

實作

1.資料行加入checkbox、超連結、button

很常見的功能,請參考:Datatables学习笔记——columns.render

在呼叫$( selector ).DataTable()初始化時,可以在columns属性中實現,也可以在columnDefs属性中實現。

jquery DataTables有很多資料行設定既可以寫在columns也可以寫在columnDefs

兩者差別為,columns要資料行一個一個設定,columnDefs則是多個資料行共用同一個設定,如下↓

/*同時設定兩個資料行禁用排序*/ 
columnDefs: [{
                    targets: [0,4],
                    orderable: false
}]

以加入checkbox、超連結、button的情況來說,既然在columns都已經定義好資料行繫結,如果寫在columnDefs有種分開設定的雜亂感

我個人習慣寫在columns裡

完整View代碼↓

※這次加入deferRender:true的參數,因為此DataTables代碼為Client Side模式透過Ajax取回資料到前端(有可能很多筆),但實際上DataTables預設一頁才顯示10~100筆,避免效能瓶頸
請參考:延迟渲染(deferRender)


<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <title>Client Side 完整 排序、分頁、查詢(DataSource使用Ajax)
    展示資料行加入checkbox、button、Hyperlink
    </title> 
    <!--引用dataTables.css-->
    <link rel="stylesheet" href="https://cdn.datatables.net/1.10.16/css/jquery.dataTables.min.css" />
</head>
<body>
     
    @using (Html.BeginForm("", "", FormMethod.Post, new { name = "myForm" }))
    {
        <label>MyTitle:</label> <input type="text" value="" name="MyTitle" /><br />
        <label>MyMoney:</label> <input type="text" value="" name="MyMoney" /><br />
        <button type="button" id="btnQuery"> 查詢</button>
    }
     
    <table id="myDataTalbe" class="display">
        <thead> 
            <tr>
                <th>
                    <input type="checkbox" name="chkAll" /> <!--全選、全勾消checkbox-->
                </th>
                <th>#</th>
                <th>MyTitle</th>
                <th>MyMoney</th>
                <th>操作</th>
            </tr>
        </thead>
    </table>



    <!--引用jQuery核心-->
    <script type="text/javascript" src="https://code.jquery.com/jquery-3.3.1.js"></script>
    <!--引用jquery dataTables.js-->
    <script type="text/javascript" src="https://cdn.datatables.net/1.10.16/js/jquery.dataTables.min.js"></script>

    <script type="text/javascript">
    
    //刪除資料
    function DelData(data)
    {
      if(confirm(data+" 是否刪除?")){
          //todo ajax Delete data(自行發揮)

          //todo ajax Delete callback function(自行發揮)
          $("#btnQuery").click();//重新查詢更新畫面
      }
    }//end DelData Func

        $(function () {
         
            let table =
                $("#myDataTalbe").DataTable({ 
                    searching: false,  //關閉filter功能 
                    columns: [ 
                        {
                            //這裡的data變數值為sysid,相等於obj.sysid
                            "data": "sysid", orderable: false, render: function (data, type, obj, meta)
                            {
                                return   '<input type="checkbox" value="' + data + '">';
                            }
                        },
                        { "data": "sysid" },//指定資料行繫結名稱
                         { "data": "MyTitle" },
                        { "data": "MyMoney" },
                        {
                            //這裡的data變數值為sysid,相等於row.sysid
                            data: "sysid",//資料行繫結屬性
                            orderable: false, // 禁用排序
                            render: function (data, type, row, meta) { 
                               //row為後端回傳的資料列物件、data變數相等於row.sysid,row可以抓到哪些資料行取決於後端的回傳
                                return "<a href='" +"@Url.Action("Edit","Home")"+"?sysid=" + data + "' >Edit</a> "
                                    + "<input type='button' onclick='DelData(" + data + ")'  value='Delete' />";

                            }
                        }
                     ],
                     deferRender:true

                 });

           
            //全選、全勾消
            $("input[name=chkAll]").change(function () {
              let checked =    $(this).prop("checked");
                $("#myDataTalbe > tbody input:checkbox").prop("checked", checked);
            });
            $("#btnQuery").click(function () {
                 
                $.ajax({ 
                         url: "@Url.Action("GetData3", "Home")",
                         method: "get",
                         data: $("form[name=myForm]").serialize(),
                         dataType: 'json',
                         success: function (result) {
                            //參考:https://datatables.net/reference/api/rows.add()
                            table.clear().rows.add(result).draw();
                         }

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


Controller代碼↓

     /// <summary>
     /// 每一筆資料Entity
     /// </summary>
    public class MyRecord
    {
        public int sysid { get; set; }
        public string MyTitle { get; set; }
        public int MyMoney { get; set; }

    }
    public class HomeController : Controller
    {
        /// <summary>
        /// DataSource 資料集合,通常為DB裡的資料
        /// </summary>
        private List<MyRecord> _myRecords = new List<MyRecord>();
        public HomeController()
        {//在建構子裡新增資料
            for (int i = 0; i < 300; i++)
            {
                this._myRecords.Add(new MyRecord()
                {
                    sysid = i + 1,
                    MyTitle = "MyTitle" + i,
                    MyMoney = i * 1000
                });
            }//end for 
        }
         



         public ActionResult GetData3()
        {
            //Server端即使排序,到了前端Datatables 還會再排序一次 ,所以這裡的資料無須排序 
            //直接回傳集合給前端 
            //參考:https://datatables.net/reference/api/rows.add()            
            return Json(this._myRecords, JsonRequestBehavior.AllowGet);
        }

    }

執行結果↓

※如要客製化呈現文字的話,也是在render參數設定,例如: 性別0為女生、1為男生,除非邏輯太複雜不適合寫在JS,才在Server端組好資料後回傳給DataTables做資料繫結。

2018.4.7 補充 render:function(data,type,row,meta)當中的row變數包含了Server端回傳的一筆全部資料,而不是DataTable的資料行資料

換句話說,即使沒被DataTable DataBinding到的資料,仍然可以從row變數讀取Server端的資料

如下↓ DataTable只呈現三個資料行,但實際上row變數包含了Server端回傳的一筆全部資料,官網說明:columns.render

 

2.設定下拉選單的每頁顯示幾筆

參考官網文件:lengthMenu

↓這是預設值

使用方式↓

官網第二個Example可看到陣列中又包含兩個陣列

那個「-1」和「All」,前者指的是下拉選單的value、後者「All」是下拉選單的文字

另外,需留意pageLength(每頁顯示幾筆),預設就會指派lengthMenu的第一個值給它,所以無須另外設定,亂給pageLength值會發生奇怪的現象

官網說明↓

2018.4.5追記,發現如果使用$.extend()為 $.fn.dataTable.defaults設定lengthMenu預設值的話,同時pageLength也要設定,否則會出現如下情況

正確代碼↓

$.extend(true, $.fn.dataTable.defaults, {
	 
    //必須同時設定pageLength和lengthMenu預設值
    pageLength: 25,
    lengthMenu: [25, 50, 100],//下拉選單每頁顯示幾筆
    
});
 
 
3.變更DataTables樣式

現在滿多網站都已使用Bootstrap框架,DataTables也支援Bootstrap樣式

可參考以下文章:

https://datatables.net/manual/styling/bootstrap (Bootstrap 3樣式)

https://datatables.net/examples/styling/bootstrap4 (Bootstrap 4樣式)

4.為DataTables設定預設值

如果覺得每次初始化$(selector).DataTable();,設定都重覆的話,例如:多國語系、關閉filter、關閉orderMulti功能

可以另行新增一支.js檔,把重覆的、共用設定都寫進入該.js,網頁再引用該.js檔來使用

參考官網文件:Setting defaults

2018.4.4 追記

Is there a way to disable initial sorting for jquery DataTables?

2018.4.6 追記

預設DataTables發出Ajax如果發生錯誤是會跳出alert() dialog

照著官網做:7. Warning: Ajax error

便可以把alert()改成錯誤訊息輸出到瀏覽器的console介面(畢竟客戶看不懂alert()的錯誤訊息XD)

還有若DataTables發出的Ajax,Server端登入逾時情況的寫法↓ (搭配我的另一篇文章使用:[ASP.MVC] 當jQuery Ajax呼叫遇上Login Timeout的處理 )

2018.4.10追記如何判斷DataTable當中是否有資料

可以在drawCallback事件裡利用 count() 方法判斷

範例↓

  drawCallback: function (settings)
  {
   if (settings.iDraw >= 2)
   {//通常執行了button click 查詢之後
    let api = this.api();
    if (api.data().count() >= 1)
    {//查有資料
       //Do Something..

      } else {
        //查無資料
        //Do Something..

     }
                            
    }//end if 
                     

   }

drawCallback事件裡還有一項重要寫法需留意↓

    drawCallback: function (settings)
                  { //因為DataTable ServerSide 每次發Ajax會刷新DOM(thead、tbody內的),使用jQuery要重新註冊事件
                        
                    //Bootstrap tooltip
                    $('[data-toggle="tooltip"]').tooltip();
                           
                  },

2024-05-14 追記:在Server Side回傳自定義參數,從前端DataTable的Callback function取得該自定義參數的值

Asp.net MVC 片段範例如下 ※實務上請把複雜的商業邏輯寫在後端處理完畢,才把結果值回傳給前端顯示

而在前端取得該自定義參數有兩種方法(擇一即可),以個人情況比較適合寫在drawCallback function,因為我的xhr.dt(Ajax callback function)已被作為共用函式

執行結果↓

2018.4.11 追記,如何為資料行加class、資料列加class

資料行要加class,可參考:columns.className

資料列要加class(通常為了高亮某一資料列使用),前端做法:createdRow事件,Server端做法:How To Add RowId and RowClass on Datatable

前端範例Code↓

 createdRow: function( row, data, dataIndex ) {
                     //row為html element
                     //data為Server端回傳的一筆物件(即使沒和資料行DataBinding的資料也可從data變數讀取) 
                     if(data.yourProperty==="SomeString")
                        {
                           $(row).addClass('highlight');
                        } 
            }

Server端範例Code (ASP.net MVC) ↓

public ActionResult Query_Table(string yourCondition,//前端DataTable傳給Server端的查詢條件 
            int draw, int start, int length //→此三個為DataTables自動傳遞參數
         )
        {
 
            int recordsTotal=0;
            List<yourObject> pagedData = new List<yourObject>();
             //回傳Json資料
            var returnObj =
              new
              {
                  draw = draw,
                  recordsTotal = recordsTotal,//資料總筆數
                  recordsFiltered = recordsTotal,
                  data = from p in pagedData//分頁後的資料 
                         select new
                         { 
                             DT_RowClass = "testClass"//前端的tr就會加上class
                         }
              };

            return Content(JsonConvert.SerializeObject(returnObj), "application/json");
        }//end DataTables

2022.1.5 追記,若遇到columns裡設定width無作用↓

解法:改成在jQuery DOM Ready事件裡設定DataTable 欄位的width,例如↓

$('thead > tr> th:nth-child(1)').css({ "min-width": "80px", "max-width": "80px" });

 

 

結語

jQuery DataTables系列文暫此告一段落,至目前為止介紹的功能,我自覺應該都很夠用XD

未來工作上如有遇到地雷、新的需求,會再不定期更新文章