ExtJS的表格做的非常强大,但是ExtJS的源码相当庞大当框架内部出现问题的时候非常难查找到解决办法。最近因为学习的需要,我们在使用ExtJSP制作公司内部的管理系统,但是在使用ExtJS自带的examples中的gird中的infinite-scroll时,却出现了“Ext.data.PageMap.getRange(): PageMap asked for range which it does not have”的错误,最终只有通过重载它自身的方法才解决问题。
环境描述:ext-4.2.1.883,谷歌浏览器调试工具(火狐浏览器需要使用fireBug)
错误描述:由于引用ExtJSP不同的包会出现不同的提示这里就以ext-all-dev.js和ext-dev.js两种不同的引用方式来说明。
当引用ext-all-dev.js时错误如下图描述:
当引用ext-dev.js时错误如下图描述:
两种引用方式都在说明一个问题:[E] Ext.data.PageMap.getRange(): PageMap asked forrange which it does not have。
解决办法:通过debug Ext的代码最终查找到 ext-4.2.1.883/src/view/Table.js 中的方法“renderRow”出错(这是引用完整ExtJS代码ext-dev.js时的情况,如果引用了ext-all-dev.js,那么“renderRow”在150317行),这是类'Ext.view.Table'中的一个方法。
通过重载Ext.view.Table中的方法解决问题,代码如下:
Ext.override(Ext.view.Table, {
renderRow: function(record, rowIdx, out) {
var me = this,
isMetadataRecord = rowIdx === -1,
selModel = me.selModel,
rowValues = me.rowValues,
itemClasses = rowValues.itemClasses,
rowClasses = rowValues.rowClasses,
cls,
rowTpl = me.rowTpl;
// Set up mandatory properties on rowValues
rowValues.record = record;
rowValues.recordId = record.internalId;
rowValues.recordIndex = rowIdx;
rowValues.rowId = me.getRowId(record);
rowValues.itemCls = rowValues.rowCls = '';
if (!rowValues.columns) {
rowValues.columns = me.ownerCt.columnManager.getColumns();
}
itemClasses.length = rowClasses.length = 0;
// If it's a metadata record such as a summary record.
// So do not decorate it with the regular CSS.
// The Feature which renders it must know how to decorate it.
if (!isMetadataRecord) {
itemClasses[0] = Ext.baseCSSPrefix + "grid-row";
if (selModel && selModel.isRowSelected) {
//正是这里出错,原来的方法是
//selModel.isRowSelected(rowIdx + 1)
//从而导致PageMap的越界错误
if (selModel.isRowSelected(rowIdx)) {
itemClasses.push(me.beforeSelectedItemCls);
}
if (selModel.isRowSelected(record)) {
itemClasses.push(me.selectedItemCls);
}
}
if (me.stripeRows && rowIdx % 2 !== 0) {
rowClasses.push(me.altRowCls);
}
if (me.getRowClass) {
cls = me.getRowClass(record, rowIdx, null, me.dataSource);
if (cls) {
rowClasses.push(cls);
}
}
}
if (out) {
rowTpl.applyOut(rowValues, out);
} else {
return rowTpl.apply(rowValues);
}
}
});
在重载这个方法之后,可能会影响其它的grid,但是在目前的使用中其它grid正常运行,没有出现任何问题!
其它问题:关于这个问题有许多人都在这个版本中遇到,但是据说在5.0之后的收费版中已经不存在了。
可以参考以下两篇文章的描述:
https://www.sencha.com/forum/showthread.php?264733-Grid-with-Infinite-Scroling-in-4.2.1-Reload-Function&p=979464&viewfull=1
http://www.4byte.cn/question/601040/get-rid-of-pagemap-asked-for-range-which-it-does-not-have-exception.html--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
测试代码(Java):
index.jsp:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>Welcome</title>
<link rel="stylesheet" type="text/css" href="ext42/resources/css/ext-all.css" />
<script type="text/javascript" src="ext42/ext-all-dev.js"></script>
<script type="text/javascript" src="ext42/locale/ext-lang-zh_CN.js"></script>
<script type="text/javascript" charset="UTF-8" src="js/test.js"></script>
</head>
<body>
</body>
</html>
test.js(也就是把ext-4.2.1.883/examples/grid/infinite-scroll.js做了简化):
Ext.require([
'Ext.grid.*',
'Ext.data.*',
'Ext.util.*',
'Ext.grid.plugin.BufferedRenderer'
]);
Ext.onReady(function(){
Ext.override(Ext.view.Table, {
renderRow: function(record, rowIdx, out) {
var me = this,
isMetadataRecord = rowIdx === -1,
selModel = me.selModel,
rowValues = me.rowValues,
itemClasses = rowValues.itemClasses,
rowClasses = rowValues.rowClasses,
cls,
rowTpl = me.rowTpl;
// Set up mandatory properties on rowValues
rowValues.record = record;
rowValues.recordId = record.internalId;
rowValues.recordIndex = rowIdx;
rowValues.rowId = me.getRowId(record);
rowValues.itemCls = rowValues.rowCls = '';
if (!rowValues.columns) {
rowValues.columns = me.ownerCt.columnManager.getColumns();
}
itemClasses.length = rowClasses.length = 0;
// If it's a metadata record such as a summary record.
// So do not decorate it with the regular CSS.
// The Feature which renders it must know how to decorate it.
if (!isMetadataRecord) {
itemClasses[0] = Ext.baseCSSPrefix + "grid-row";
if (selModel && selModel.isRowSelected) {
//正是这里出错,原来的方法是
//selModel.isRowSelected(rowIdx + 1)
//从而导致PageMap的越界错误
if (selModel.isRowSelected(rowIdx)) {
itemClasses.push(me.beforeSelectedItemCls);
}
if (selModel.isRowSelected(record)) {
itemClasses.push(me.selectedItemCls);
}
}
if (me.stripeRows && rowIdx % 2 !== 0) {
rowClasses.push(me.altRowCls);
}
if (me.getRowClass) {
cls = me.getRowClass(record, rowIdx, null, me.dataSource);
if (cls) {
rowClasses.push(cls);
}
}
}
if (out) {
rowTpl.applyOut(rowValues, out);
} else {
return rowTpl.apply(rowValues);
}
}
});
Ext.define('ForumThread', {
extend: 'Ext.data.Model',
fields: ['key', 'value'],
idProperty: 'key'
});
// create the Data Store
var store = Ext.create('Ext.data.Store', {
id: 'store',
model: 'ForumThread',
remoteGroup: true,
// allow the grid to interact with the paging scroller by buffering
buffered: true,
leadingBufferZone: 0,
pageSize: 100,
proxy: {
// load using script tags for cross domain, if the data in on the same domain as
// this page, an Ajax proxy would be better
type: 'ajax',
url: 'DataServer',
reader: {
root: 'data',
totalProperty: 'totalCount'
},
// sends single sort as multi parameter
simpleSortMode: true,
// sends single group as multi parameter
simpleGroupMode: true,
// This particular service cannot sort on more than one field, so grouping === sorting.
groupParam: 'sort',
groupDirectionParam: 'dir'
},
sorters: [{
property: 'key',
direction: 'ASC'
}],
autoLoad: true,
listeners: {
// This particular service cannot sort on more than one field, so if grouped, disable sorting
groupchange: function(store, groupers) {
var sortable = !store.isGrouped(),
headers = grid.headerCt.getVisibleGridColumns(),
i, len = headers.length;
for (i = 0; i < len; i++) {
headers[i].sortable = (headers[i].sortable !== undefined) ? headers[i].sortable : sortable;
}
},
// This particular service cannot sort on more than one field, so if grouped, disable sorting
beforeprefetch: function(store, operation) {
if (operation.groupers && operation.groupers.length) {
delete operation.sorters;
}
}
}
});
var grid = Ext.create('Ext.grid.Panel', {
width: 700,
height: 500,
collapsible: true,
title: 'ExtJS.com - Browse Forums',
store: store,
loadMask: true,
selModel: {
pruneRemoved: false
},
multiSelect: true,
viewConfig: {
trackOver: false
},
features:[{
ftype: 'grouping',
hideGroupedHeader: false
}],
// grid columns
columns:[{
xtype: 'rownumberer',
width: 100,
sortable: false
},{
text: "key",
dataIndex: 'key',
width: 100,
sortable: true
},{
text: "value",
dataIndex: 'value',
align: 'center',
flex: 1,
sortable: false
}],
renderTo: Ext.getBody()
});
});
DataServer.java(服务器端servlet代码):
package com.ext.servlet;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class DataServer extends HttpServlet {
/**
* Constructor of the object.
*/
public DataServer() {
super();
}
/**
* Destruction of the servlet. <br>
*/
public void destroy() {
super.destroy(); // Just puts "destroy" string in log
// Put your code here
}
/**
* The doGet method of the servlet. <br>
*
* This method is called when a form has its tag value method equals to get.
*
* @param request the request send by the client to the server
* @param response the response send by the server to the client
* @throws ServletException if an error occurred
* @throws IOException if an error occurred
*/
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
PrintWriter out = response.getWriter();
String pageStr = request.getParameter("page");
String startStr = request.getParameter("start");
String limitStr = request.getParameter("limit");
pageStr = pageStr==null || pageStr.equals("") ? "0":pageStr;
startStr = startStr==null || startStr.equals("") ? "0":startStr;
limitStr = limitStr==null || limitStr.equals("") ? "100":limitStr;
int page = Integer.valueOf(pageStr);
int start = Integer.valueOf(startStr);
int limit = Integer.valueOf(limitStr);
int count = 600;
StringBuffer buffer = new StringBuffer();
buffer.append("{'totalCount':'"+count+"','data':[");
for (int i=start; i< start+limit; i++){
buffer.append("{'key':'key-"+i+"','value':'val-"+i+"'},");
}
buffer.delete(buffer.lastIndexOf(","), buffer.length());
buffer.append("]}");
out.write(buffer.toString());
//out.write("<html>sadf</html>");
out.flush();
out.close();
}
/**
* The doPost method of the servlet. <br>
*
* This method is called when a form has its tag value method equals to post.
*
* @param request the request send by the client to the server
* @param response the response send by the server to the client
* @throws ServletException if an error occurred
* @throws IOException if an error occurred
*/
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
this.doGet(request, response);
}
/**
* Initialization of the servlet. <br>
*
* @throws ServletException if an error occurs
*/
public void init() throws ServletException {
// Put your code here
}
}