ASP.NET MVC 5 ABP DataTables (二)
JS DataTables 这个组件绑定数据必须要有自己的返回数据格式。但是ABP返回的格式直接绑定是错误。添加DataTables JS 扩展、数据加载等。ABP 原作者已经在ABP.ZERO CORE 项目有相应的应用。
DataTable JS 扩展:
1 /************************************************************************ 2 * datatables AJAX 扩展 * 3 *************************************************************************/ 4 (function ($) { 5 6 if (!$.fn.dataTableExt) { 7 return; 8 } 9 10 var doAjax = function (listAction, requestData, callbackFunction, settings) { 11 var inputFilter = {}; 12 13 //设置表过滤器 14 if (listAction.inputFilter) { 15 inputFilter = $.extend(inputFilter, listAction.inputFilter()); 16 } 17 18 //设置分页过滤器 19 if (settings.oInit.paging) { 20 inputFilter = $.extend(inputFilter, { 21 maxResultCount: requestData.length, 22 skipCount: requestData.start 23 }); 24 } 25 26 //排序过滤器 27 if (requestData.order && requestData.order.length > 0) { 28 var orderingField = requestData.order[0]; 29 if (requestData.columns[orderingField.column].data) { 30 inputFilter.sorting = requestData.columns[orderingField.column].data + " " + orderingField.dir; 31 } 32 } 33 34 35 if (listAction.ajaxFunction) { 36 listAction.ajaxFunction(inputFilter) 37 .done(function (result) { 38 settings.rawServerResponse = result; 39 callbackFunction({ 40 recordsTotal: result.totalCount, //总数 41 recordsFiltered: result.totalCount, 42 data: result.items //数据项 43 }); 44 }); 45 } 46 } 47 48 if (!$.fn.dataTable) { 49 return; 50 } 51 52 $.extend(true, $.fn.dataTable.defaults, { 53 ajax: function (requestData, callbackFunction, settings) { 54 if (!settings) { 55 return; 56 } 57 58 if (!settings.oInit) { 59 return; 60 } 61 62 if (!settings.oInit.listAction) { 63 return; 64 } 65 66 doAjax(settings.oInit.listAction, requestData, callbackFunction, settings); 67 } 68 }); 69 //重新加载 70 $.fn.dataTable.Api.register('ajax.reloadPage()', function () { 71 this.ajax.reload(null, false); 72 }); 73 74 })(jQuery);
$.extend(true, $.fn.dataTable.defaults, { language: { url: '/Abp/Framework/scripts/Datatables/Translations/Chinese (Simplified, China).json' }, lengthMenu: [5, 10, 25, 50, 100, 250, 500], pageLength: 10, responsive: true, searching: false, pagingType: "bootstrap_full_number", dom: 'rt<"bottom"ilp><"clear">', order: [] });
1 /************************************************************************ 2 * RECORD-ACTIONS extension for datatables * 3 *************************************************************************/ 4 (function ($) { 5 6 if (!$.fn.dataTableExt) { 7 return; 8 } 9 10 var _createDropdownItem = function (record, fieldItem) { 11 var $li = $('<li/>'); 12 var $a = $('<a/>'); 13 14 if (fieldItem.text) { 15 $a.html(fieldItem.text); 16 } 17 18 if (fieldItem.action) { 19 $a.click(function (e) { 20 e.preventDefault(); 21 22 if (!$(this).closest('li').hasClass('disabled')) { 23 fieldItem.action({ 24 record: record 25 }); 26 } 27 }); 28 } 29 30 $a.appendTo($li); 31 return $li; 32 } 33 34 var _createButtonDropdown = function (record, field) { 35 var $container = $('<div/>') 36 .addClass('btn-group') 37 .addClass('dropdown') 38 .addClass('action-button'); 39 40 var $dropdownButton = $('<button/>') 41 .html(field.text) 42 .addClass('dropdown-toggle') 43 .attr('data-toggle', 'dropdown') 44 .attr('aria-haspopup', 'true') 45 .attr('aria-expanded', 'true'); 46 47 if (field.cssClass) { 48 $dropdownButton.addClass(field.cssClass); 49 } 50 51 var $dropdownItemsContainer = $('<ul/>').addClass('dropdown-menu'); 52 53 for (var i = 0; i < field.items.length; i++) { 54 var fieldItem = field.items[i]; 55 56 if (fieldItem.visible && !fieldItem.visible({ record: record })) { 57 continue; 58 } 59 60 var $dropdownItem = _createDropdownItem(record, fieldItem); 61 62 if (fieldItem.enabled && !fieldItem.enabled({ record: record })) { 63 $dropdownItem.addClass('disabled'); 64 } 65 66 $dropdownItem.appendTo($dropdownItemsContainer); 67 } 68 69 if ($dropdownItemsContainer.find('li').length > 0) { 70 $dropdownItemsContainer.appendTo($container); 71 $dropdownButton.appendTo($container); 72 } 73 74 if ($dropdownItemsContainer.children().length === 0) { 75 return ""; 76 } 77 78 return $container; 79 }; 80 81 var _createSingleButton = function (record, field) { 82 $(field.element).data(record); 83 84 if (field.visible === undefined) { 85 return field.element; 86 } 87 88 var isVisibilityFunction = typeof field.visible === "function"; 89 if (isVisibilityFunction) { 90 if (field.visible()) { 91 return field.element; 92 } 93 } else { 94 if (field.visible) { 95 return field.element; 96 } 97 } 98 99 return ""; 100 }; 101 102 var _createRowAction = function (record, field, tableInstance) { 103 if (field.items && field.items.length > 1) { 104 return _createButtonDropdown(record, field, tableInstance); 105 } else if (field.element) { 106 var $singleActionButton = _createSingleButton(record, field); 107 if ($singleActionButton != "") { 108 return $singleActionButton.clone(true); 109 } 110 } 111 112 return ""; 113 } 114 115 var hideColumnWithoutRedraw = function (tableInstance, colIndex) { 116 tableInstance.fnSetColumnVis(colIndex, false, false); 117 } 118 119 var hideEmptyColumn = function(cellContent, tableInstance, colIndex) { 120 if (cellContent == "") { 121 hideColumnWithoutRedraw(tableInstance, colIndex); 122 } 123 }; 124 125 var renderRowActions = function (tableInstance, nRow, aData, iDisplayIndex, iDisplayIndexFull) { 126 var columns; 127 if (tableInstance.aoColumns) { 128 columns = tableInstance.aoColumns; 129 } else { 130 columns = tableInstance.fnSettings().aoColumns; 131 } 132 133 if (!columns) { 134 return; 135 } 136 137 var cells = $(nRow).children("td"); 138 139 for (var colIndex = 0; colIndex < columns.length; colIndex++) { 140 var column = columns[colIndex]; 141 if (column.rowAction) { 142 var $actionContainer = _createRowAction(aData, column.rowAction, tableInstance); 143 hideEmptyColumn($actionContainer, tableInstance, colIndex); 144 145 var $actionButton = $(cells[colIndex]).find(".action-button"); 146 if ($actionButton.length === 0) { 147 $(cells[colIndex]).append($actionContainer); 148 } 149 } 150 } 151 }; 152 153 var _existingApiRenderRowActionsFunction = $.fn.dataTableExt.oApi.renderRowActions; 154 $.fn.dataTableExt.oApi.renderRowActions = function (tableInstance, nRow, aData, iDisplayIndex, iDisplayIndexFull) { 155 if (_existingApiRenderRowActionsFunction) { 156 _existingApiRenderRowActionsFunction(tableInstance, nRow, aData, iDisplayIndex, iDisplayIndexFull); 157 } 158 159 renderRowActions(tableInstance, nRow, aData, iDisplayIndex, iDisplayIndexFull); 160 }; 161 162 if (!$.fn.dataTable) { 163 return; 164 } 165 166 var _existingDefaultFnRowCallback = $.fn.dataTable.defaults.fnRowCallback; 167 $.extend(true, $.fn.dataTable.defaults, { 168 fnRowCallback: function (nRow, aData, iDisplayIndex, iDisplayIndexFull) { 169 if (_existingDefaultFnRowCallback) { 170 _existingDefaultFnRowCallback(this, nRow, aData, iDisplayIndex, iDisplayIndexFull); 171 } 172 173 renderRowActions(this, nRow, aData, iDisplayIndex, iDisplayIndexFull); 174 } 175 }); 176 177 })(jQuery);
1 { 2 "sProcessing": "处理中...", 3 "sLengthMenu": "显示 _MENU_ 项结果", 4 "sZeroRecords": "没有匹配结果", 5 "sInfo": "显示第 _START_ 至 _END_ 项结果,共 _TOTAL_ 项", 6 "sInfoEmpty": "显示第 0 至 0 项结果,共 0 项", 7 "sInfoFiltered": "(由 _MAX_ 项结果过滤)", 8 "sInfoPostFix": "", 9 "sSearch": "搜索:", 10 "sUrl": "", 11 "sEmptyTable": "表中数据为空", 12 "sLoadingRecords": "载入中...", 13 "sInfoThousands": ",", 14 "oPaginate": { 15 "sFirst": "首页", 16 "sPrevious": "上页", 17 "sNext": "下页", 18 "sLast": "末页" 19 }, 20 "oAria": { 21 "sSortAscending": ": 以升序排列此列", 22 "sSortDescending": ": 以降序排列此列" 23 } 24 }
ABP应用层 (只是做了演示的Demo)
[AutoMapTo(typeof(Project))] public class CreateProjectDto { public string Name { get; set; } public string Address { get; set; } } public class GetProjectInput : PagedAndSortedResultRequestDto, IShouldNormalize { public void Normalize() { if (string.IsNullOrEmpty(Sorting)) { Sorting = "Name"; } } } [AutoMapFrom(typeof(Project)), AutoMapTo(typeof(Project))] public class ProjectDto:EntityDto<long> { public string Name { get; set; } public string Address { get; set; } }
1 2 public interface IProjectAppService : IAsyncCrudAppService<ProjectDto, long, PagedResultRequestDto, CreateProjectDto, ProjectDto> 3 { 4 PagedResultDto<ProjectDto> GetProject(GetProjectInput dto); 5 } 6 public class ProjectAppService : AsyncCrudAppService<Project, ProjectDto, long, PagedResultRequestDto, CreateProjectDto, ProjectDto>, IProjectAppService 7 { 8 public ProjectAppService(IRepository<Project, long> repository) : base(repository) 9 { 10 11 } 12 13 public PagedResultDto<ProjectDto> GetProject(GetProjectInput input) 14 { 15 var query = Repository.GetAllList(); 16 var queryAllCount = query.Count; 17 18 19 var users = query.OrderBy(o=>o.Address).Skip(input.SkipCount).Take(input.MaxResultCount) 20 .ToList(); 21 22 var projectDotlist = ObjectMapper.Map<List<ProjectDto>>(users); 23 24 return new PagedResultDto<ProjectDto>(queryAllCount, projectDotlist); 25 26 } 27 }
ABP展示层
1 @section Scripts{ 2 <script src="~/lib/datatables/datatables.all.min.js"></script> 3 <script src="~/lib/datatables/plugins/bootstrap/datatables.bootstrap.js"></script> 4 <script src="~/Abp/Framework/scripts/Datatables/datatables.ajax.js"></script> 5 <script src="~/Abp/Framework/scripts/Datatables/datatables.defaults.js"></script> 6 <script src="~/Abp/Framework/scripts/Datatables/datatables.record-actions.js"></script> 7 <script src="~/Views/Projects/index.js"></script> 8 } 9 @section styles 10 { 11 <link href="~/lib/datatables/datatables.min.css" rel="stylesheet" /> 12 <link href="~/lib/datatables/plugins/bootstrap/datatables.bootstrap.css" rel="stylesheet" /> 13 } 14 <div class="row margin-bottom-5"> 15 <div class="col-xs-6"> 16 <div class="page-head"> 17 <div class="page-title"> 18 <h1> 19 <span>@L("Project")</span> <small>@L("ProjectHeaderInfo")</small> 20 </h1> 21 </div> 22 </div> 23 </div> 24 </div> 25 26 <div class="portlet light margin-bottom-0"> 27 <div class="portlet-title portlet-title-filter"> 28 <div class="inputs inputs-full-width"> 29 <div class="portlet-input"> 30 <form> 31 <div class="row"> 32 <div class="col-xs-6"> 33 34 </div> 35 <div class="col-xs-6"> 36 <div class="form-group"> 37 <button id="RefreshProjectButton" class="btn btn-primary blue"><i class="fa fa-refresh"></i> @L("Refresh")</button> 38 </div> 39 </div> 40 </div> 41 </form> 42 </div> 43 </div> 44 </div> 45 <div class="portlet-body"> 46 <table id="ProjectTable" class="table table-striped table-bordered table-hover order-column"> 47 <thead> 48 <tr> 49 <th>@L("Actions")</th> 50 <th>@L("RoleName")</th> 51 <th>@L("CreationTime")</th> 52 </tr> 53 </thead> 54 </table> 55 </div> 56 </div>
1 (function () { 2 $(function () { 3 var _$projectsTable = $('#projectsTable'); 4 var _projectService = abp.services.app.project; 5 var dataTable = _$projectsTable.DataTable({ 6 paging: true, 7 serverSide: true, 8 processing: false, 9 listAction: { 10 ajaxFunction: _projectService.getProject 11 }, 12 columnDefs: [ 13 { 14 targets: 0, 15 data: null, 16 orderable: false, 17 autoWidth: false, 18 defaultContent: '', 19 rowAction: { 20 cssClass: 'btn btn-xs btn-primary blue', 21 text: '<i class="fa fa-cog"></i> ' + 'Actions' + ' <span class="caret"></span>', 22 items: [ 23 ] 24 } 25 }, 26 { 27 targets: 1, 28 data: "name" 29 30 }, 31 { 32 targets: 2, 33 data: "address" 34 } 35 ] 36 }); 37 $('#RefreshprojectsButton').click(function (e) { 38 e.preventDefault(); 39 getprojects(); 40 }); 41 function getprojects() { 42 dataTable.ajax.reload(); 43 } 44 }); 45 })();
然后调试数据展示成功。