前两篇:(列表页的动态条件搜索,我是如何做列表页的)分别介绍了我们是如何做后端业务系统数据展示类的列表页以及动态搜索的,那么还剩下最重要的一项:数据展示。数据展示一般包含三部分:

  • 数据列头
  • 数据行
  • 分页统计信息,分页导航

技术依赖项:基于angularjs的MVVM模式,后台是spring mvc。


  数据表格需求:

  • 需要支持列头的排序
  • 需要支持单页操作,局部更新(angular model更新),比如更新某行数据成功后,自动更新当前行的数据,而不需要刷新页面或者另外请求后台数据。
  • 需要支持数据逻辑运算以及复杂的html格式的数据,比如根据不同的数据值展示不同的按钮,文本等,展示的文本需要经过特定的逻辑运算等。
  • 需要有统计信息以及分页展示

第三方的组件:

  • jquery.datatable http://www.datatables.net/

最终展示的结果是html table,优点是支持嵌套表格等复杂功能,缺点是加载的文件大,且不能满足上面的需求angular model更新,对于复杂数据展示控制起来也比较复杂,需要额外的js编码工作。

  • angular ui-grid https://github.com/angular-ui/ui-grid/wiki/Getting-started

最终展示的结果是div,与angularjs兼容性很好,能支持表格在线编辑,缺点同样也是不能满足上面的需求angular model更新,对于复杂数据展示控制起来也比较复杂,需要额外的js编码工作。

     第三方组件的特点就是功能多,但有些看起来很高级的功能我们基本上都不用,比如在线表格数据的编辑,嵌套表格等。我们必须的功能只有这些:排序,数据展示,分页,如果能支持angular model更新更好。所以我决定结合html table,angularjs来完成上面的需求。

数据加载:

   由于我们的数据动态查询方案的存在,决定了大部分页面前后台交互的模式是相同的,所以采用angular service来提供一个listService供列表页使用。主要是分页大小的选择框,以及定义了一些可配置的参数,比如执行查询的请求地址,由于我们的动态查询以表单提交,所以是将整个表单参数序列化之后再加上分页相关信息然后提交到后端查询。

angular.module('app.service', ['app.constant']).service('$listService', function () {var $scopeLocal = {};var pageSizeList = [{"text": "10","value": "10"}, {"text": "20","value": "20"}];var defaultOptions = {beforeSend: function () {},callback: function ($scope, data) {},error: function () {},pageSize: pageSizeList[0].value,searchFormId: "searchForm",};this.init = function ($scope, option) {var options = $.extend({}, defaultOptions, option);$scopeLocal = $scope;$scopeLocal.pageSizeList = pageSizeList;$scopeLocal.pageRequest = {"pageNum": 1, "pageSize": options.pageSize};$scopeLocal.pageRequest.getResponse = function (orderBy) {var requestData = $("#" + options.searchFormId + "").serialize();var url = options.listUrl + "?" + requestData + "&pageNum=" + $scopeLocal.pageRequest.pageNum + "&pageSize=" + $scopeLocal.pageRequest.pageSize;if(angular.isDefined($scopeLocal.pageRequest.orderBy)&&$scopeLocal.pageRequest.orderBy!=""){url+="&orderBy="+$scopeLocal.pageRequest.orderBy;}$.ajax({type: "POST",url: url,dataType: 'json',async: false,beforeSend: options.beforeSend,error: options.error,success: function (data) {$scopeLocal.pageResponse = data;$scopeLocal.content = data.list;options.callback($scopeLocal, data);}});};         this.get = function () {$scopeLocal.pageRequest.getResponse();};};})

使用时,只需要注入listService,然后配置上参数即可:

mainApp.controller('manageCtrl', function ($scope, $http, $listService) {var options = {listUrl:"<c:url value="/theme/getAllByPage"/>"};$listService.init($scope, options);$listService.get();});   

数据排序:
  列头排序的方案是在列头上增加排序字段,通过angular directive来实现。排序的图片以及变换的样式是从jquery.datatable借鉴过来,逻辑并不复杂,无非就是显示排序标签以及根据用户的点击变换排序图标。

angular.module('app.directives', []).directive("sortName", [ function() {return {restict : "A",link : function(scope, element, attrs) {var sortName = attrs["sortName"];var sortType = attrs["sortType"];if (!angular.isString(sortName) || sortName == "")return;if (!angular.isString(sortType) || sortType == "") {element.removeClass("sorting").removeClass("sorting_asc").removeClass("sorting_desc").addClass("sorting").attr("sort-type","asc");}$(element).bind("click", function(){var thisObj=$(this);var sortType = thisObj.attr("sort-type");if (!angular.isString(sortName) || sortName == "")return;if (!angular.isString(sortType) || sortType == "")return;var orderBy = sortName + " " + sortType;scope.pageRequest.orderBy=orderBy;scope.pageRequest.getResponse();if (sortType == "asc") {thisObj.removeClass("sorting").removeClass("sorting_asc").removeClass("sorting_desc").addClass("sorting_asc").attr("sort-type","desc");} else if (sortType == "desc") {thisObj.removeClass("sorting").removeClass("sorting_asc").removeClass("sorting_desc").addClass("sorting_desc").attr("sort-type","asc");}thisObj.siblings().each(function (){var item=$(this);if(typeof(item.attr("sort-name"))!="undefined"){item.removeClass("sorting").removeClass("sorting_asc").removeClass("sorting_desc").addClass("sorting");}});scope.$apply();});}}
} ]);

一个scope作用域的问题,在directive中获得的scope比较特殊,它的值变更不会影响外层页面上的$scope。因为我们需要在用户点击排序按钮后进行数据更新,所以我们需要调用$apply方法将scope的变化传播出去。

html中只需要在列头指定排序字段即可实现排序功能:sort-name,值是需要排序的字段:

<th class="col-md-1" sort-name ="id">编号</th>
<th class="col-md-4" sort-name ="name">名称</th>

数据展示:
  直接在页面中采用table来布局,数据行采用angularjs来做加载。table布局的优点在于:直观上很清晰,处理某些特殊数据行时也比较容易,重要的是能够很容易的支持angular model 更新。

<table id="datatableTheme" cellpadding="0" cellspacing="0" border="0"class="datatable table table-striped table-bordered table-hover"><thead><tr><th>编号</th><th>名称</th><th>状态</th><th>描述</th><th>操作</th></tr></thead><tbody><tr ng-repeat="item in content"><td ng-bind="item.id"></td><td ng-bind="item.name"></td><td><div ng-show="item.status=='1'"><span class="label label-success">启用</span></div><div ng-show="item.status =='0'"><span class="label label-danger">禁用</span></div></td><td ng-bind="item.description"></td><td><a href="javascript:void(0)" data-toggle="modal" ng-click="edit(item.id)"data-original-title="编辑"> <spanclass="label label-primary">编辑</span></a><a href="javascript:void(0)" ng-show="item.status=='0'" ng-click="enabled(item)"> <spanclass="label label-primary">启用</span></a><a href="javascript:void(0)" ng-show="item.status=='1'" ng-click="enabled(item)"> <spanclass="label label-primary">禁用</span></a></td></tr></tbody></table>

分页信息:
  采用angularjs ui自带的uib-pagination。由于需要支持当前页记录大小的选择,如果每个页面都需要包含分页相关内容,这样代码会比较冗余,于时很容易的我们可以借助angular directive来解决:

angular.module('app.directives', []).directive("pagerFooter", [ function() {return {restrict : "A",link : function(scope, element) {return null;},templateUrl : "../app/template/pagerFooter.html"}
} ])

<meta charset="UTF-8"><div class="row form-inline"><div class="col-md-6"><span> 每页<ui-select ng-model="pageRequest.pageSize" ng-change="pageRequest.getResponse()"  theme='select2' style="min-width:35px;" ><ui-select-match>{{$select.selected.text}}</ui-select-match>                          <ui-select-choices repeat="item.value as item  in (pageSizeList | filter: $select.search)"><div ng-bind="item.text"></div></ui-select-choices></ui-select>                                                    条记录 总共<span ng-bind="pageResponse.total"></span>条记录 </span></div><div class="col-md-6 text-right"><uib-paginationtotal-items="pageResponse.total"ng-model="pageRequest.pageNum" max-size="4" class="pagination-sm" boundary-links="true" force-ellipses="false"first-text="首页"last-text="末页"previous-text="上一页"next-text="下一页"num-pages="pageResponse.pages"ng-change="pageRequest.getResponse()"items-per-page="pageRequest.pageSize"></uib-pagination></div></div>

使用时,我们只需要这样指定:加一个pager-footer的属性。

 <div class="box-body" pager-footer></div>

写这个指令时遇到一个编码问题,模板页中出现的中文,在spring mvc环境下调用中乱码,最终在web.xml中增加配置得以解决:

<mime-mapping><extension>html</extension><mime-type>text/html;charset=utf-8</mime-type></mime-mapping> 

目前还有一个疑问没有得到解决,就是模板页中必须还要指定<meta charset="UTF-8">,否则也会显示成乱码,回头找时间整体研究下spring mvc下的编码。

数据行数据的model更新

以避免通过二次请求或者刷新页面来重新加载数据。比如行数据中有状态一栏,操作列会根据状态值动态显示启用或者停用按钮,当用户点击启用按钮操作成功后,当前数据行的状态栏数据需要动态更新,且不需要请求后台也不需要刷新页面,我们可以非常容易的通用ng-bind来让其自动更新:

操作列绑定事件:

 <td><a href="javascript:void(0)" data-toggle="modal" ng-click="edit(item.id)"data-original-title="编辑"> <spanclass="label label-primary">编辑</span></a><a href="javascript:void(0)" ng-show="item.status=='0'" ng-click="enabled(item)"> <spanclass="label label-primary">启用</span></a><a href="javascript:void(0)" ng-show="item.status=='1'" ng-click="enabled(item)"> <spanclass="label label-primary">禁用</span></a></td>                 

操作成功后更新model,页面数据自动更新。

$scope.enabled=function(theme){bootbox.confirm("确认操作吗?", function (flag) {if (flag) {var status=theme.status==1?0:1;var model={id:theme.id,status:status};$http.post("<c:url value="/theme/enabled"/>",model).success(function(ret){if (ret.err) {bootbox.alert(ret.err);}else {theme.status=status;bootbox.alert("操作成功!");}});}});};

列表页最终效果

上述的功能虽然不能解决所有场景的问题(嵌套表格,在线编辑表格,换肤等),但常见的业务操作均能满足,足够简单,不需要依赖第三方组件,重要的是能够完成其它js组件所不擅长的model更新场景以及复杂列的运算以及控制。我目前还在寻找其它的组件,如果有即能满足上述的需求又使用简单那么也是可以替换的,但做为学习总结总结倒也不错。

通过angularjs的directive以及service来实现的列表页加载排序分页相关推荐

  1. AngularJS封装指令实现下拉刷新自动翻页加载数据

    目前PC的网页越来越流行瀑布流的下拉刷新自动加载数据,本文来讲解一下. 滚动翻页基本原理就是判断scrollTop和offsetHeight之和 大于等于 scrollHeight. 一.不适用Jqu ...

  2. 开机登录失败 提示user profile service服务未能登录,无法加载用户配置文件

    开机登录失败 提示"user profile service服务未能登录,无法加载用户配置文件" 问题解决办法 [问题描述] Windows系统开机后,在用户登录界面输入密码无法正 ...

  3. 计算机没有用户配置文件,win7提示User Profile Service服务未能登录,无法加载用户配置文件如何解决...

    最近有用户在启动Windows7系统的时候欢迎界面出现"User Profile Service服务未能登录,无法加载用户配置文件"的提示,怎么都没办法进入到桌面,那么如何解决呢? ...

  4. 电脑显示服务器未能登陆 无法加载用户配置,win7系统提示User Profile Service服务未能登录,无法加载用户配置文件的解决方法...

    很多小伙伴都遇到过win7系统提示User Profile Service服务未能登录,无法加载用户配置文件的困惑吧,一些朋友看过网上零散的win7系统提示User Profile Service服务 ...

  5. User Profile Service服务未登录,无法加载用户配置文件的解决方案

    最近驱动人生用户反映win10开机提示User Profile Service服务未登录,无法加载用户配置文件.造成这个问题的原因通常是用户配置文件.文件夹被删除或用户配置文件损坏及用户已停止或禁用此 ...

  6. 提示“User Profile Service服务未能登录,无法加载用户配置文件。”

    提示"User Profile Service服务未能登录,无法加载用户配置文件." 注:本文由Colin撰写,版权所有!转载请注明原文地址,谢谢合作! 针对此问题我首先做的是登入 ...

  7. angularJS+requireJS实现controller及directive的按需加载

    最近因为项目的比较大,需要加载的js文件较多,为了提高首屏页面的加载速度,需要对js文件进行按需加载,然后网上参考了一些资料,自己也深入研究一番之后,实现了按需加载控制器js文件及指令js文件的效果: ...

  8. Ocata Neutron代码分析(六)——APIRouter的初始化(1)加载core plugin和service plugin...

    在分析api-paste.ini时,曾分析到wsgi app neutronapiapp_v2_0是直接调用/neutron/api/v2/router.py中APIRouter的factory方法: ...

  9. 我的世界未能从服务器注册表数据,【经验之谈】“User Profile Service 服务未能登录,无法加载用户配置文件”实战历程...

    某一天你打开PC,开机正常,可当你输入正确的密码回车,却发现Vista或Win7拒绝让你登录,提示"User Profile Service服务未能登录.无法加载用户配置文件.", ...

  10. AngularJS中Directive指令系列 - 基本用法

    参考: https://docs.angularjs.org/api/ng/service/$compile http://www.zouyesheng.com/angular.html Direct ...

最新文章

  1. MySQL增量订阅消费组件Canal POC
  2. Linux RPM 相关
  3. linux常用的内核镜像格式
  4. hibernate教程--持久化类状态详解
  5. SQL Server 大数据搬迁之文件组备份还原实战
  6. win8, VS2013 .NET 4.5在哪找svcutil.exe?
  7. 关于CodeReview
  8. 记腾讯一面 | 掘金技术征文
  9. golang中的切片及内存拷贝
  10. bzoj 4709: [Jsoi2011]柠檬(分段DP+决策单调性)
  11. 日常开发中的几个常用跨域处理方式
  12. FFmpeg录制视频黑屏
  13. opencv中关于cvtColor函数性能测试
  14. 公安大数据智能化平台(大数据人工智能公司)
  15. 优化vue项目打包的chunk.js 和 chunk-vonder.js
  16. sd卡数据恢复源码android,SD卡数据恢复非常简单,想学的看过来!
  17. Android 11.0 长按电源键直接关机屏蔽关机对话框
  18. miui patchrom项目 生成原厂包问题 /卡死现象For MTK CPU
  19. Java枚举—枚举进阶
  20. 保姆级教程:群晖nas内网穿透之ipv6/ipv4 ddns+frp双管齐下!

热门文章

  1. python 运算符及 字符串格式化输出方式 if条件语句判断 random函数简单应用练习
  2. java反射机制的实现机制_Java反射机制实践
  3. principle文本导入oracle,动效设计Principle:初识界面
  4. 昆明钟英高中2021年高考成绩查询,昆明官渡钟英中学2021年排名
  5. mysql grant 用户权限
  6. 使用oracle执行txt语句,oracle常用SQL语句.txt
  7. scp创建远程目录_如何在 HPC 硬件上远程运行大型仿真?
  8. 项目管理工具_项目管理工具MS Project使用经验分享
  9. mysql优化必知(mysql的语句执行顺序)
  10. hdu 5437Alisha’s Party(优先队列)