原文地址:http://blog.csdn.net/nuaazdh/article/details/37660377,转载请勿标明,多谢~

前言

Symfony2.x本来应该许配给Bootstrap的,可是考虑到本人前端基础实在太差,使用Bootstrap还要使用DIV来布局,前端部分又得使用jQuery,因此就委屈求全使用了EasyUI。EasyUI界面不够炫,但确实方便。不过,之前没有用过,开始做还是遇到不少问题。闲话少叙,文章的主要内容是Symfony2.x作为框架,Doctrine从后台获取数据,并以json格式返回给前端。前端使用EasyUI的界面。其中重点是解决datagrid的异步加载的分页问题,如果没有分页需求可参见另一篇博文:Symfony2.x + EasyUI datagrid Ajax方式实现数据交互。

正文

一、分页问题的出现

首先明确一下为何会有分页问题。前一篇博文中给出的解决方案虽然是ajax异步加载,但是采用的是自动分页,即数据从服务端传来,直接赋值给datagrid控件。如果你的datagrid控件设置了pagination = true,它会自动加载一个分页条,实现自动分页。既然都自动分页了,那还有讨论这个问题干嘛? 假设你有这样的需求,后台的数据量很大,即使使用ajax数据量也太多,这样前端其实响应还是比较慢的,我们需要后端分页后每次只传给一页的数据量。其次,如果你的数据太多,它自动分页了,你要添加“编辑”、“删除”的按钮,编辑后需要更新显示,那么前面的做法就不行了,只能刷新整个页面,但是刷新后会自动显示第一页,不是你当时编辑的页面,怎么办?

二、 分页问题解决方案

解决方案: 将datagrid 控件和 分页pagination控件分开,datagrid 不再设置 pagination = true, 手动实现点击下一页的js代码。当用户点击”下一页“时,发出ajax请求,服务端根据传入的page (页的序号)和 limits(每页的记录个数)查询数据库,返回json结果。前端将返回的结果绑定到datagrid控件中。具体有以下几点:

① 前端(模板)中将 datagrid 和 pagination 控件分开,设置 手动完成切换页面的触发onSelectPage()函数;

② 在 onSelectPage()函数中,发出ajax请求,将页号(page)和每页记录数(limits或者rows)发送给服务端;

③ 服务端根据page和limits参数,做查询操作,返回从 (page-1)*limits 开始的limits个记录;

④ 将后端返回的数据绑定到前端的datagrid中,异步刷新;

⑤ 当前端发生单个记录的编辑操作时,编辑完成后,调用$('#pp').pagination('select'); (其中pp就是pagination控件的id),自动刷新当前页;

三、代码

路由文件和布局模板直接省略,直接看功能页面的twig文件和后端的获取分页数据的代码:

1. 前端twig模板代码
{% extends 'AcmeStoreBundle::layout.html.twig' %}

{% block content %}
	<!--这里是你的datagrid控件,注意不要设置 pagination = true 了 -->
	<table id="dg" title="Title name" class="easyui-datagrid" style="width:auto;height:0"
			toolbar="#toolbar" rownumbers="true" fitColumns="true" singleSelect="true">
	    <thead>
	        <tr>
	        	<th data-options="field:'id',width:0,align:'left'">ID</th>
	            <th data-options="field:'name',width:60,align:'left'">名称</th>
	            
	        </tr>
	    </thead>
	</table>
	<!-- 这里是你的pagination 控件,用于分页 -->
	<div id="pp" class="easyui-pagination" style="border:1px solid #ccc;"
        data-options="
        	total: 200,Pagelist: [10,20,50,100],onSelectPage: function(pageNumber,pageSize){ // 页面切换动作
            		getDataByPageRows(pageNumber,pageSize);	  
            }">
	</div>
	<!-- 这里省略了form表单的定义 -->
	<script>		
        
        $(function(){     // 页面初始加载的时候,显示第一页,10条记录   
        	getDataByPageRows(1,10);           
        });  
		
        function saveItem(){	// 前端form发生编辑保存动作
			// 表单数据转化为 json格式的字符串
      		var raw_str = JSON.stringify($('#fm').serializeArray());
			$('#fm').form('submit',{
				onSubmit: function(){		  
					$.ajax({
						type: "POST",dataType: 'json',// 格式为json
						url: "{{ path('xxx_update') }}",// 执行动作的路由名称,在routing.yml中定义
						data: {
							data_p: raw_str,},error: function(){
							alert('对不起,保存数据失败!');
							$('#dlg').dialog('close');
						},success: function(data,textStatus,jqXHR){
							$('#dlg').dialog('close');
							$.messager.alert('提示信息:',data,'info');	
								$('#pp').pagination('select');
							}
					});//ajax
				}
			});
	    }	    

	    /*
		* ajax 方式向后端请求第pageNum页,共rowLimit条记录
		*/
	    function getDataByPageRows(pageNum,rowsLimit)
	    {
	    	pageNum = pageNum || 1;		// 设置默认的页号
	    	rowsLimit = rowsLimit || 10;// 设置默认的每页记录数
	    	$.ajax({
				type: "POST",dataType: 'html',// 注意格式是html,不是json
				url: "{{ path('xxx_show') }}",data: {
					page: pageNum,rows: rowsLimit,error: function(){	// ajax请求失败
					$.messager.show({
		                title:'失败信息',msg:'load data Failed',timeout:0,showType:'fade'
		            });
				},jqXHR){	// 请求成功,将返回的数据(一页的记录数)绑定到 datagrid控件
					var jsonObj = $.parseJSON(data);
					var count = jsonObj.count;				// 总记录个数
					var data_t = eval('['+jsonObj.data+']');
					$('#dg').datagrid('loadData',data_t);
					$('#pp').pagination({
						total: count,// 由于显示 ”共XXX条记录” 等信息用
						pageNumber: pageNum,// 
					});
				}
			});//ajax	    
	    }  
	    
    </script>
	
	<!-- 这里可以添加多个 toolbar  -->
	<div id="toolbar">
		<div style="margin-bottom:5px">
			<a href="javascript:void(0)" class="easyui-linkbutton" iconCls="icon-add" plain="true" onclick="newItem()">新建</a>
			<a href="javascript:void(0)" class="easyui-linkbutton" iconCls="icon-edit" plain="true" onclick="editItem()">编辑</a>
			<a href="javascript:void(0)" class="easyui-linkbutton" iconCls="icon-remove" plain="true" onclick="deleteItem()">删除</a>
        </div>
	</div>
    
{% endblock %}

2. 后端更新操作和显示一页的PHP代码
<?PHP
// src/Acme/StoreBundle/Controller/XXXController.PHP
namespace Acme\StoreBundle\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Doctrine\ORM\Tools\Pagination\Paginator;

use Acme\StoreBundle\Entity\XXXEntity;

class XXXController extends Controller{
		
	/**
	*@Route("/XXX/",name="XXX_index")
	*@Template("AcmeStoreBundle:XXXEntity:index.html.twig")
	*/
	public  function  showAction(Request $request)
	{	
		// 仅处理ajax响应
		if($request->isXmlHttpRequest()){
			// 获取请求参数
			$rows = $request->request->get('rows');
			$page = $request->request->get('page');
			// 设置请求参数的默认值,若前端js中处理了,此处可以省略
			isset($rows)?($rows):($rows=10);
			isset($page)?($page):($page=1);
			// 这是是使用Doctrine获取分页的关键代码
			$em = $this->getDoctrine()->getManager();
			$dql = 'SELECT p FROM AcmeStoreBundle:XXXEntity p ORDER BY p.id ASC';
			$query = $em->createquery($dql)
						->setFirstResult(($page-1)*$rows)
						->setMaxResults($rows);
			$paginator  = new Paginator($query,true);
			// json 字符串
			$json_str = "";
			$i = 0; 
			$len = count($paginator);
			foreach ($paginator as  $item)
			{
				$i++;
				// 这里提供日期和时间类型转换函数,供需要的参考
				//$publishDateStr = date_format($item->getPublishDate(),'Y-m-d');
				//$signitureTimeStr = date_format($item->getSignitureTime(),'Y-m-d H:i:s');
				$publishTypestr = addslashes($item->getPublishType());
				$json_str.="{id:"."\"{$item->getId()}\","
				."name:"."\"{$item->getName()}\",";
				if($i!=$len){// 对最后一个记录做特殊处理:省略右花括号}后的逗号,$json_str .= "lastColumnName:"."\"{$cutsizeStr}\"},";
				}else{
					$json_str .= "lastColumnName:"."\"{$cutsizeStr}\"}";
				}
			}
			// 返回记录的总数,和当前页的所有记录数据,记录总数会在分页控件中用到,"共xxx项,当前显示xxx-xxx项"
			return new Response(json_encode(array('count' => $len,'data' => $json_str)));
			
		}else{
			return new Response('Illigal request');
		}
	}
	
	/**
	*@Route("/XXX/",name="XXX_index")
	*@Template("AcmeStoreBundle:XXXEntity:index.html.twig")
	*/
	public function updateAction(Request $request)
	{
	if ($request->isXmlHttpRequest()) {
			$json_data =  $request->request->get('data_p');
			$data = json_decode($json_data);	// 解析 json数据
 			// 获取各个属性值
			$id = (int)$data[0]->{"value"};
			$name = $data[1]->{"value"};
			// 提供两个日期和时间的处理函数,供需要参考
			//$publishDate = date_create_from_format('Y/m/j',$data[2]->{"value"});
			//$signitureTime = date_create_from_format('Y/m/j H:i:s',$data[3]->{"value"});			
			// 在 Repository中根据id查询记录	
			$em = $this->getDoctrine()->getEntityManager();
			$item = $em->getRepository('AcmeStoreBundle:XXXEntity')->find($id);
			
			if(!$item){ // 记录不存在,可以创建,这样一个updateAction完成了前端“新建”和“编辑”两个功能
				$item = new XXXEntity();				
				$item->setName($name);
				//$item->setpublishDate($publishDate);
				//$item->setSignitureTime($signitureTime);
				$em->persist($item);
				$em->flush();
				return  new Response(json_encode('创建项目成功,ID:'.$item->getId()));
			}else{ // 记录存在,更新值
				$item->setName($name);
				//$item->setpublishDate($publishDate);
				//$item->setSignitureTime($signitureTime);
				$em->flush();
				// 注意返回的数据格式也是json_encode()处理过的,否则前端ajax获取失败
 				return  new Response(json_encode('更新 ID = '.$id.' 文件信息成功!'));
			return $response;
			}
		}else{
			return  new Response(json_encode('非法的更新请求!'),400);
		}
	}
}
?>

3. 页面效果

Firefox的Firebug大家都比较熟悉,不用推荐了,贴一下效果,easyui的界面都差不多,呵

Symfony2.x EasyUI Ajax 异步加载DataGrid 分页的更多相关文章

  1. 前端实现背景虚化但内容清晰且自适应 的实例代码

    这篇文章主要介绍了前端实现背景虚化但内容清晰且自适应 的实例代码,需要的朋友可以参考下

  2. ios – UIScrollView的平滑自定义分页

    我在UIScrollView中有两个(可能更多)视图,并希望使用分页.当我尝试使用UIScrollView的默认分页选项时出现问题,因为视图具有不同的宽度,无法正确分页.所以我已经实现了一个有效的自定义分页代码.但是,当滚动较慢时,它不会按预期运行.(它回到没有动画的原始位置.)以下是我目前通过uiscrollviewdelegate进行自定义分页的方法我想要的是:是)我有的:解决方法尝试下面的自

  3. ios – 使用子视图控制器分页滚动视图

    使用分页实现水平滚动视图的最佳做法是什么,每页有一个视图控制器?由于iOS5具有用于视图控制器容器/包含的API,因此PageControl示例仍然是实现此功能的最佳方式吗?

  4. 可可触摸 – 启用预览和分页的UICollectionView

    在AppStore中显示搜索结果时,我正在尝试模仿苹果公司的功能.(参考:http://searchengineland.com/apple-app-search-shows-only-one-result-at-a-time-133818)它显示像卡中的详细应用程序信息,并且它被分页.当中间的一个活动卡片和滚动视图的分页行为仍然完整时,我被困在如何使上一张和第二张卡片显示.我已经尝试使用UICo

  5. ios – 启用了内容插入的UIScrollView分页工作很奇怪

    我创建了具有内容插入的UIScrollView.第一次,scrollView.contentOffset.x为-160.0但是奇怪的问题是当我点击scrollView(黄色区域)时,内容偏移x值将重置为0并显示为这样.我尝试过几次,但是点击滚动视图会将内容偏移量重置为0.我该如何防止这种情况?解决方法UIScrollView分页通过滚动与scrollView宽度相同的页面(在您的情况下为480个宽

  6. 应用程序关闭时的iOS任务

    我正在构建一个应用程序,通过ajax将文件上传到服务器.问题是用户很可能有时不会有互联网连接,并且客户希望在用户重新连接时安排ajax调用.这可能是用户在离线时安排文件上传并关闭应用程序.应用程序关闭时可以进行ajax调用吗?

  7. UIKit框架-高级控件Swift版本: 10.UIWebView方法/属性详解

    前面我们已经讲解完了UINavigationController的一些常用属性以及方法,现在让我们来看看一个关于网络的UIWebView.1.UIWebView的常用属性常用类型2.UIWebView的代理方法3.代码示范首先我们要使用storyBoard布局界面关联控件遵守代理协议自定义UIWebVIew实现代理方法在ViewDidLoad方法中实现PS:UIWebView继承与UIView,并

  8. swift+storyboard+UIImageview入门

    更新记录:该Storyboard教程由CarolineBegbie更新iOS8和Swift相关内容。Storyboard是最先在iOS5引入的一项振奋人心的特性,大幅缩减构建App用户界面所需的时间。要介绍Storyboard是什么,我打算从这张图讲起。这就是使用Storyboard的力量。Storyboard通过新的原型表项和静态表项特性,让处理表视图的工作更加轻松。Storyboard使自动布局更易用。接下来我们看一下Storyboard,点击项目浏览器中的Main.storyboard就可以在Int

  9. 使用RxSwift进行分页API调用

    如何实现这一点的任何建议将非常感谢…

  10. android – Phonegap本地构建 – jquery ajax错误:readystate 0 responsetext status 0 statustext error

    解决方法您是否在索引文件中包含了内容安全元标记?

随机推荐

  1. xe-ajax-mock 前端虚拟服务

    最新版本见Github,点击查看历史版本基于XEAjax扩展的Mock虚拟服务插件;对于前后端分离的开发模式,ajax+mock使前端不再依赖后端接口开发效率更高。CDN使用script方式安装,XEAjaxMock会定义为全局变量生产环境请使用xe-ajax-mock.min.js,更小的压缩版本,可以带来更快的速度体验。

  2. vue 使用 xe-ajax

    安装完成后自动挂载在vue实例this.$ajaxCDN安装使用script方式安装,VXEAjax会定义为全局变量生产环境请使用vxe-ajax.min.js,更小的压缩版本,可以带来更快的速度体验。cdnjs获取最新版本点击浏览已发布的所有npm包源码unpkg获取最新版本点击浏览已发布的所有npm包源码AMD安装require.js安装示例ES6Module安装通过Vue.use()来全局安装示例./Home.vue

  3. AJAX POST数据中文乱码解决

    前端使用encodeURI进行编码后台java.net.URLDecoder进行解码编解码工具

  4. Koa2框架利用CORS完成跨域ajax请求

    实现跨域ajax请求的方式有很多,其中一个是利用CORS,而这个方法关键是在服务器端进行配置。本文仅对能够完成正常跨域ajax响应的,最基本的配置进行说明。这样OPTIONS请求就能够通过了。至此为止,相当于仅仅完成了预检,还没发送真正的请求呢。

  5. form提交时,ajax上传文件并更新到&lt;input&gt;中的value字段

  6. ajax的cache作用

    filePath="+escape;},error:{alert;}});解决方案:1.加cache:false2.url加随机数正常代码:网上高人解读:cache的作用就是第一次请求完毕之后,如果再次去请求,可以直接从缓存里面读取而不是再到服务器端读取。

  7. 浅谈ajax上传文件属性contentType = false

    默认值为contentType="application/x-www-form-urlencoded".在默认情况下,内容编码类型满足大多数情况。在这里,我们主要谈谈contentType=false.在使用ajax上传文件时:在其中先封装了一个formData对象,然后使用post方法将文件传给服务器。说到这,我们发现在JQueryajax()方法中我们使contentType=false,这不是冲突了吗?这就是因为当我们在form标签中设置了enctype=“multipart/form-data”,

  8. 909422229_ajaxFileUpload上传文件

    ajaxFileUpload.js很多同名的,因为做出来一个很容易。我上github搜AjaxFileUpload出来很多类似js。ajaxFileUpload是一个异步上传文件的jQuery插件传一个不知道什么版本的上来,以后不用到处找了。语法:$.ajaxFileUploadoptions参数说明:1、url上传处理程序地址。2,fileElementId需要上传的文件域的ID,即的ID。3,secureuri是否启用安全提交,默认为false。4,dataType服务器返回的数据类型。6,error

  9. AJAX-Cache:一款好用的Ajax缓存插件

    原文链接AJAX-Cache是什么Ajax是前端开发必不可少的数据获取手段,在频繁的异步请求业务中,我们往往需要利用“缓存”提升界面响应速度,减少网络资源占用。AJAX-Cache是一款jQuery缓存插件,可以为$.ajax()方法扩展缓存功能。

  10. jsf – Ajax update/render在已渲染属性的组件上不起作用

    我试图ajax更新一个有条件渲染的组件。我可以确保#{user}实际上是可用的。这是怎么引起的,我该如何解决呢?必须始终在ajax可以重新呈现之前呈现组件。Ajax正在使用JavaScriptdocument.getElementById()来查找需要更新的组件。但是如果JSF没有将组件放在第一位,那么JavaScript找不到要更新的内容。解决方案是简单地引用总是渲染的父组件。

返回
顶部