ABP之展示層(Datatables分頁)

 在前面的隨筆中,已經介紹了ABP的增刪改查的操做,可是對於查詢的數據並無進行分頁,只是進行粗糙的展現,今天的隨筆中將摸索進行分頁展現。這裏打算使用的分頁插件是DataTables,這是一款比較強大的表格插件。javascript

在之前咱們後臺手動分頁的時候,須要前臺傳入兩個重要的分頁參數:PageIndex和PageSize(顯示第幾頁的數據和每頁顯示的數量),這是必須的量的參數。分頁做爲一個頁面展現的基礎功能,ABP框架已經對分頁功能進行了一些方便性的操做,爲咱們提供了一些有助於分頁的接口和Dto,Dto是什麼?這個在前面的隨筆中已經研究過了,這裏就再也不重複。css

一 .ABP中的分頁接口html

在ABP中總共爲咱們提供了三個分頁的接口:IPagedResultRequest、ISortedResultRequest、ILimitedResultRequest三個接口java

 

從上面的三個接口中咱們看到了三個重要的變量,這就是咱們分頁和排序中常常用到的量。jquery

二. 實現分頁的Dtoajax

在咱們免費的ABP中模板中,也就是隻能找到這麼三個接口,對咱們分頁來講確實並無提供了多大的方便,可是在ABP Zero中已經對三個接口進行了相應的實現,只是zero是收費的。在這裏咱們能夠模仿zero在咱們ABP模板中添加上分頁的Dto,而且爲DataTables這個插件定製分頁Dto。json

 

詳細的代碼api

 1 1.PagedInputDto
 2  public class PagedInputDto : IPagedResultRequest
 3     {
 4         /// <summary>
 5         /// 每頁顯示的行數
 6         /// </summary>
 7         [Range(1, AppConsts.MaxPageSize)]
 8         public int MaxResultCount { get; set; }
 9         /// <summary>
10         /// 跳過數量=MaxResultCount*頁數
11         /// </summary>
12         [Range(0, int.MaxValue)]
13         public int SkipCount { get; set; }
14 
15         public PagedInputDto()
16         {
17             MaxResultCount = AppConsts.DefaultPageSize;
18         }
19     }
20 2. PagedAndFilteredInputDto
21     public class PagedAndFilteredInputDto : IPagedResultRequest
22     {
23         [Range(1, AppConsts.MaxPageSize)]
24         public int MaxResultCount { get; set; }
25 
26         [Range(0, int.MaxValue)]
27         public int SkipCount { get; set; }
28 
29         public string Filter { get; set; }
30 
31         public PagedAndFilteredInputDto()
32         {
33             MaxResultCount = AppConsts.DefaultPageSize;
34         }
35     }
36 3. PageAndSortedInputDto
37     public class PagedAndSortedInputDto : PagedInputDto, ISortedResultRequest
38     {
39         public string Sorting { get; set; }
40 
41         public PagedAndSortedInputDto()
42         {
43             MaxResultCount = AppConsts.DefaultPageSize;
44         }
45     }
46 4.PagedSortedAndFilteredInputDto
47     public class PagedSortedAndFilteredInputDto : PagedAndSortedInputDto
48     {
49         public string Filter { get; set; }
50         //接收DataTables的參數
51         public int Draw { get; set; }
52         public int Length
53         {
54             get
55             {
56                 return this.MaxResultCount;
57             }
58 
59             set
60             {
61                 this.MaxResultCount = value;
62             }
63         }
64         public int Start
65         {
66             get
67             {
68                 return this.SkipCount;
69             }
70 
71             set
72             {
73                 this.SkipCount = value;
74             }
75         }
76     }
77 5.DataTablesPageOutPutDto
78    [Serializable]
79     public class DataTablesPagedOutputDto<T>:PagedResultDto<T>
80     {
81         public int Draw { get; set; }
82 
83         /// <summary>
84         /// 過濾後的記錄數(沒有就是所有),這個是必須的參數
85         /// </summary>
86         public int RecordsFiltered { get; set; }
87 
88         public int RecordsTotal { get { return this.TotalCount; } }
89       
90         public DataTablesPagedOutputDto(int totalCount, IReadOnlyList<T> items)
91           : base(totalCount, items)
92         {
93             this.RecordsFiltered = totalCount;
94         }
95     }

 

其中PagedSortedAndFilteredInputDto和DataTablesPageOutPutDto分別是爲了適應DataTables的需求定製的兩個類,Input的類中Start、Length、Draw、Filter都是爲了接收DataTables傳遞過來的參數,在OutPut類中定義了RecordsFiltered和recordsTotal和Draw這些都是DataTables須要的參數。說了這麼多,仍是先看一下DataTables這插件再說。緩存

三.DataTables分頁服務器

在這裏咱們使用的服務端分頁,詳細的內容可查看官網的具體介紹:http://www.datatables.club/manual/server-side.html

(1)Dto的請求參數

固然參數還有許多,可是主要的參數也就是上面的那幾個,尤爲是已經圈出來的這三個,就能夠完成分頁功能了,若是須要進行排序或者添加按照字段的搜索的功能,那麼就須要用到下面的字段了,咱們這裏只是使用分頁功能。

(2)Dto的返回參數

 

 經過了上面DataTables官網的介紹,咱們已經清楚了咱們Dto中定義的參數的做用了,不知道你們有沒有一點困惑,就是Draw參數究竟是幹什麼的???哈哈哈,咱們在DataTables中已經找到了答案,他是防止跨站腳本攻擊的,關於他的賦值,只要給他賦值一個整數就能夠了。

三.在ABP中使用DataTables實現分頁

View

Index的具體代碼

@using Abp.Authorization.Users
@using StudyABPProject.Web.Startup
@model IList<StudyABPProject.Movie.Dto.MovieTicketDto>
@{
    ViewBag.CurrentPageName = PageNames.Movies; // The menu item will be active for this page.
}
@section scripts
    {
    <script src="~/lib/jquery-daterangepicker/daterangepicker.js" asp-append-version="true"></script>
    <script src="~/view-resources/Views/Movie/Index.js" asp-append-version="true"></script>

    <link href="~/lib/jquery-daterangepicker/daterangepicker.css" rel="stylesheet" />
    <link href="~/lib/datatables/jquery.dataTables.min.css" rel="stylesheet" />
    <script src="~/lib/datatables/jquery.dataTables.min.js"></script>
}

<div class="row clearfix">
    <div class="col-lg-12 col-md-12 col-sm-12 col-xs-12">
        <div class="card">
            <div class="header">
                <h2>
                    @L("Movie")
                </h2>
                <ul class="header-dropdown m-r--5">
                    <li class="dropdown">
                        <a href="javascript:void(0);" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">
                            <i class="material-icons">more_vert</i>
                        </a>
                        <ul class="dropdown-menu pull-right">
                            <li><a id="RefreshButton" href="javascript:void(0);" class="waves-effect waves-block"><i class="material-icons">refresh</i>Refresh</a></li>
                        </ul>
                    </li>
                </ul>
            </div>
            <div class="body table-responsive">
                <button type="button" class="btn btn-primary  waves-effect  waves-float pull-right" data-toggle="modal" data-target="#MovieTicketCreateModal">
                    <i class="material-icons">添加</i>
                </button>
                <table id="MovieTable" name="MovieTable"></table>
            </div>
        </div>
    </div>
</div>

<div class="modal fade" id="MovieTicketCreateModal" tabindex="-1" role="dialog" aria-labelledby="UserCreateModalLabel" data-backdrop="static">
    <div class="modal-dialog" role="document">
        <div class="modal-content">
            <div class="modal-header">
                <h4 class="modal-title">
                    <span>@L("CreateMovieTicket")</span>
                </h4>
            </div>
            <div class="modal-body">
                <form name="movieCreateForm" role="form" novalidate class="form-validation">
                    <div class="tab-content">
                        <div role="tabpanel" class="tab-pane animated fadeIn active" id="create-user-details">
                            <div class="row clearfix" style="margin-top:10px;">
                                <div class="col-sm-12">
                                    <div class="form-group form-float">
                                        <div class="form-line">
                                            <input class="form-control" type="text" name="MovieName" required maxlength="256" minlength="2">
                                            <label class="form-label">@L("MovieName")</label>
                                        </div>
                                    </div>
                                </div>
                            </div>
                            <div class="row clearfix">
                                <div class="col-sm-12">
                                    <div class="form-group form-float">
                                        <div class="form-line">
                                            <input type="text" name="MovieActor" class="form-control" required maxlength="256">
                                            <label class="form-label">@L("MovieActor")</label>
                                        </div>
                                    </div>
                                </div>
                            </div>
                            <div class="row clearfix">
                                <div class="col-sm-12">
                                    <div class="form-group form-float">
                                        <div class="form-line">
                                            <input type="datetime" name="StartTime" class="form-control" required>
                                            @*<label class="form-label">@L("StartTime")</label>*@
                                        </div>
                                    </div>
                                </div>
                            </div>
                            <div class="row clearfix">
                                <div class="col-sm-12">
                                    <div class="form-group form-float">
                                        <div class="form-line">
                                            <input type="datetime" id="EndTime" name="EndTime" class="form-control">
                                            @*<label class="form-label">@L("EndTime")</label>*@
                                        </div>
                                    </div>
                                </div>
                            </div>
                            <div class="row clearfix">
                                <div class="col-sm-12">
                                    <div class="form-group form-float">
                                        <div class="form-line">
                                            <input type="number" id="Money" name="Money" class="form-control">
                                            <label class="form-label">@L("Money")</label>
                                        </div>
                                    </div>
                                </div>
                            </div>
                        </div>
                    </div>
                    <div class="modal-footer">
                        <button type="button" class="btn btn-default waves-effect" data-dismiss="modal">取消</button>
                        <button type="submit" id="btnSave" class="btn btn-primary waves-effect">保存</button>
                    </div>
                </form>
            </div>
        </div>
    </div>
</div>
<div class="modal fade" id="MovieTicketEditModal" tabindex="-1" role="dialog" data-backdrop="static">
    <div class="modal-dialog" role="document">
        <div class="modal-content">
        </div>
    </div>
</div>

 

Js

關於js代碼的位置我也按照框架中的位置放在了view-resources,話說Js代碼離View有點遠~~~

Index.Js中的主要代碼

(function () {
    $(function () {

        var _movieService = abp.services.app.movieTicket;
        var _$modal = $('#MovieTicketCreateModal');
        var _$form = _$modal.find('form[name="movieCreateForm"]');

        _$form.validate({
            rules: {
                MovieName:
                {
                    required:true
                },
                StartTime: "required",
                EndtTime:
                {
                    required: true
                },
                MovieActor: "required"
                ,Money:"required"
            },
            messages: {
                MovieName: {
                    required:"電影名稱不能爲空"
                },
                MovieActor: {
                    required: "演員名稱不能爲空"
                },
                StartTime: {
                    required: "開始時間不能爲空"
                },
                EndTime: {
                    required: "結束時間不能爲空"
                },
                Money: {
                    required: "票價不能爲空"
                }
            }
        });

        var dateOption = {
            locale: {

                format: 'YYYY-MM-DD HH:mm:ss',
                applyLabel: '確認',
                cancelLabel: '取消'

            },
            singleDatePicker: true,
            startDate: moment().format("YYYY-MM-DD HH:mm:ss"),
            timePicker24Hour: true,
            timePicker: true,
            autoApply: true,
            autoUpdateInput: true
        };
        $('input[name=StartTime]').daterangepicker(dateOption);
        $('input[name=EndTime]').daterangepicker(dateOption);
        $('#RefreshButton').click(function () {
            refreshUserList();
        });
      
        $('.delete-movie').click(function () {
            var movieId = $(this).attr("data-movie-id");
            var movieName = $(this).attr("data-movie-name");
            abp.message.confirm(
                "刪除電影 '" + movieName + "'?",
                function (isConfirmed) {
                    if (isConfirmed) {
                        _movieService.deleteMovie({
                            "id": movieId, "movieName": movieName,
                        }).done(function () {
                            refreshMovieList();
                        });
                    }
                }
            );
        });

        $('.edit-movie').click(function (e) {
            var movieId = $(this).attr("data-movie-id");

            e.preventDefault();
            $.ajax({
                url: abp.appPath + 'MovieTicket/EditMovieTicketModal?movieId=' + movieId,
                type: 'POST',
                contentType: 'application/html',
                success: function (content) {
                    $('#MovieTicketEditModal div.modal-content').html(content);
                },
                error: function (e) { }
            });
        });

        _$form.find('button[type="submit"]').click(function (e) {
            e.preventDefault();

            if (!_$form.valid()) {
                return;
            }

            var movie = _$form.serializeFormToObject(); 
            abp.ui.setBusy(_$modal);
            _movieService.createMovie(movie).done(function (response) {
                if (response == "No") {
                    abp.message.error("建立失敗");
                }
                else {
                    _$modal.modal('hide');
                    location.reload(true); 
                }
               
            }).always(function () {
                abp.ui.clearBusy(_$modal);
            });
        });

        _$modal.on('shown.bs.modal', function () {
            _$modal.find('input:not([type=hidden]):first').focus();
        });

        function refreshMovieList() {
            location.reload(true); //reload page to see new user!
        }

        function deleteUser(userId, userName) {
           
        }
        var CONSTANT = {
            DATA_TABLES: {
                DEFAULT_OPTION: { //DataTables初始化選項  
                    language: {
                        "sProcessing": "處理中...",
                        "sLengthMenu": "每頁 _MENU_ 項",
                        "sZeroRecords": "沒有匹配結果",
                        "sInfo": "當前顯示第 _START_ 至 _END_ 項,共 _TOTAL_ 項。",
                        "sInfoEmpty": "當前顯示第 0 至 0 項,共 0 項",
                        "sInfoFiltered": "(由 _MAX_ 項結果過濾)",
                        "sInfoPostFix": "",
                        "sSearch": "搜索:",
                        "sUrl": "",
                        "sEmptyTable": "表中數據爲空",
                        "sLoadingRecords": "載入中...",
                        "sInfoThousands": ",",
                        "oPaginate": {
                            "sFirst": "首頁",
                            "sPrevious": "上頁",
                            "sNext": "下頁",
                            "sLast": "末頁",
                            "sJump": "跳轉"
                        },
                        "oAria": {
                            "sSortAscending": ": 以升序排列此列",
                            "sSortDescending": ": 以降序排列此列"
                        }
                    },
                    autoWidth: false,   //禁用自動調整列寬  
                    stripeClasses: ["odd", "even"],//爲奇偶行加上樣式,兼容不支持CSS僞類的場合  
                    order: [],          //取消默認排序查詢,不然複選框一列會出現小箭頭  
                    processing: false,  //隱藏加載提示,自行處理  
                    serverSide: true,   //啓用服務器端分頁  
                    searching: false    //禁用原生搜索  
                },
                COLUMN: {
                    CHECKBOX: { //複選框單元格  
                        className: "td-checkbox",
                        orderable: false,
                        width: "30px",
                        data: null,
                        render: function (data, type, row, meta) {
                            return '<input type="checkbox" class="iCheck">';
                        }
                    }
                },
                RENDER: {   //經常使用render能夠抽取出來,如日期時間、頭像等  
                    ELLIPSIS: function (data, type, row, meta) {
                        data = data || "";
                        return '<span title="' + data + '">' + data + '</span>';
                    }
                }
            }
        };  
        var getQueryCondition=function(data) {  
            var param = {};  
            //組裝排序參數  
            if(data.order&&data.order.length && data.order[0]) {
            //組裝分頁參數  
            param.start = data.start;
            param.length = data.length;  
            param.draw = data.draw;  
            return param;  
        }
        var page = {
            $table: $("#MovieTable"),
            $dataTable: null,
        
            initDataPicker: function () {
                var dataOption = {
                    startDate: moment().startOf("month"),
                    "maxDate": null,
                    singleDatePicker: true
                };
                var dataOption1 = {
                    startDate: moment().endOf("month"),
                    "maxDate": null,
                    singleDatePicker: true
                };
                $("#StartTime").WIMIDaterangepicker(dataOption);
                $("#EndTime").WIMIDaterangepicker(dataOption1);
            },
            initTable: function () {
                if (!$.fn.DataTable.isDataTable("#MovieTable")) {
                    page.$datatable = page.$table.DataTable($.extend(true, {}, CONSTANT.DATA_TABLES.DEFAULT_OPTION, {
                        ajax: function (data, callback, settings) {
                            //封裝請求參數  
                            var param = getQueryCondition(data);

                            $.ajax({
                                type: "GET",
                                url: "/api/services/app/" + "movieTicket/getAllMovieTicketPage",
                                cache: false,  //禁用緩存  
                                data: param,    //傳入已封裝的參數  
                                dataType: "json",
                                success: function (response) {
                                    //封裝返回數據  
                                    var returnData = {};
                                    returnData.draw = response.result.draw;//這裏直接自行返回了draw計數器,應該由後臺返回  
                                    returnData.recordsTotal = response.result.recordsFiltered;//總記錄數  
                                    returnData.recordsFiltered = response.result.recordsFiltered;//後臺不實現過濾功能,每次查詢均視做所有結果  
                                    returnData.data = response.result.items;
                                    //調用DataTables提供的callback方法,表明數據已封裝完成並傳回DataTables進行渲染  
                                    //此時的數據需確保正確無誤,異常判斷應在執行此回調前自行處理完畢  
                                    callback(returnData);
                                },
                                error: function (XMLHttpRequest, textStatus, errorThrown) {
                                    alert("查詢失敗");
                                }
                            });
                        },
                        "paging": true,
                        //綁定數據  
                        "columns": [
                            {
                                "defaultContent": "",
                                "title": "操做",
                                "orderable": false,
                                "width": "150px",
                                "className": "text-center not-mobile",
                                "createdCell": function (td, cellData, rowData, row, col) {
                                    var $actionContent = $("<div class='action-content'>");
                                    $('<button class="btn  btn-xs">修改</button>')
                                        .appendTo($actionContent)
                                        .click(function () {
                                            alert(rowData.startTime);
                                            console.log(rowData);
                                        });
                                $('<button class="btn  btn-xs"> 刪除 </button>')
                                        .appendTo($actionContent)
                                    .click(function () {
                                        alert(rowData.id);
                                    });
                                    $(td).append($actionContent);
                               }
                            },
                            {
                                "data": "movieName",
                                "title": "電影名稱"
                            },
                            {
                                "data": "movieActor",
                                "title": "演員名稱",
                                "width": "120px",
                            },
                            {
                                "data": "startTime",
                                "title": "開始時間",
                                "render": function (data, type, full, meta) {
                                    return moment(data).format("YYYY-MM-DD HH:mm:ss");
                                }
                            },
                            {
                                "data": "endTime",
                                "title": "結束時間",
                                "render": function (data, type, full, meta) {
                                    return moment(data).format("YYYY-MM-DD HH:mm:ss");
                                }

                            },
                            {
                                "data": "money",
                                "title": "票價",
                            }
                        ], }));
//此處需調用api()方法,不然返回的是JQuery對象而不是DataTables的API對象 } else { page.$datatable.ajax.reload(); } }, init: function () { page.initTable(); } } page.init(); }); })();

 在這裏須要感謝https://blog.csdn.net/u011072139/article/details/54312414?locationnum=10&fps=1,從這篇博客類借鑑了一些Jscript代碼

注意的問題:

(1)在使用DataTables的時候,常常出現一個錯誤,錯誤的提示:沒有「length」,其實出現這個錯誤的緣由是沒有爲Data賦值,DataTables須要返回Data,而後它會自動計算length,因此只要將Data賦值並返回便可。

(2)returnData.data = response.result.items;從這行代碼中能夠看出,咱們返回的數據並非一個簡單的對象,不能直接訪問咱們在後臺傳出的屬性,多封裝了一層。

上面的代碼中只是實現了分頁的功能,關於刪除和修改並無從新實現。須要注意的是在DataTables盡心後臺訪問的時候的請求路徑url,url: "/api/services/app/" + "movieTicket/getAllMovieTicketPage",這的路徑並非具體的控制器中的方法,而是直接訪問的Application層的服務方法,這裏就涉及了ABP中動態的Js代理,還一個須要重點關注的是type必須是Get類型,不然是沒法找到訪問路徑的,這是由於在ABP中動態Js代理默認的請求方式是get。關於動態的Js代理在ABP中的應用這個將會在後面的隨筆去研究。

後臺主要的代碼

 

  public async Task<PagedResultDto<MovieTicketDto>> GetAllMovieTicketPage(MovieInputDto input)
        {
            var query = movieTicketRepository.GetAll() ;
            var totalCount =await query.CountAsync();
            var models =await query.OrderBy(input.Sorting).AsNoTracking().PageBy(input).ToListAsync();
            if (models.Count()==0)
            {
                return new DataTablesPagedOutputDto<MovieTicketDto>(0, new List<MovieTicketDto>());
            }
            var items = models.MapTo<List<MovieTicketDto>>();
            return new DataTablesPagedOutputDto<MovieTicketDto>(totalCount,items); 
        }

 

到此爲止,基本的分頁功能已經實現,下面看一下運行的效果吧

請求的數據:

 

返回的數據:

 

相關文章
相關標籤/搜索