PDA

View Full Version : [1.1] Ext.ux.data.PagingMemoryProxy



trbs
22 Aug 2007, 4:11 PM
Hi all,

Here another one of my fine Ext contributions :">

Ext.ux.data.PagingMemoryProxy
A proxy for local / in-browser data structures which supports paging / sorting / filtering / etc.

Wiki
http://extjs.com/learn/Extention:PagingMemoryProxy

Download
PagingMemoryProxy is part of one of the locale examples i wrote for the official Ext distribution, you can find it under the Ext/examples/locale folder. The User eXtension will be further developed here and can be downloaded at the url below.

See http://ido.nl.eu.org/ext-pagingmemoryproxy/ for a demo and download links.

Online Demo
You can find an example of the PagingMemoryProxy in the official Ext distribution: Multiple Languages Example (http://extjs.com/deploy/ext/examples/locale/multi-lang.html)
The PagingMemoryProxy is used in the bottom grid, that pages and sorts the long Month names of the selected language.

Todo / Future Thought

Anybody has a wish list ?? if so please add to the forum thread


Changelog

1.3 : (30-09-2007) Added customFilter config option.
1.2 : (29-09-2007) Fixed several sorting bugs, thanks to dogmatic!
1.1 : fixed sorting algoritm
1.0 : initial release as User eXtension

trbs
22 Aug 2007, 4:29 PM
i'll try to get build a comprehensive demo/example for the extension as soon as i can.

If you have a good use-case for PagingMemoryProxy which you think will make a great example, please post in this thread or PM me.

Grimsk
26 Aug 2007, 5:12 PM
hi trbs ,,

im new to Ext.. and im wandering when i should use this ux

can you explain me a situation when it 'll be good to use it?

thnks

trbs
26 Aug 2007, 5:18 PM
There's some debate on that one :)

Most of the time you'll won't use this, cause normally you get your data from the server and that will be it. But sometimes you have these corner cases where this can be useful.

Like when i wanted to create an extremely simple grid which still demonstrates grid localization with paging and sorting (possibly filtering as well), since Date.monthNames is already in memory i needed the same functionality as MemoryProxy provides only now with sorting etc.

I think this Ext.ux falls into the category; when you'll need it, you'll know it.
Before that, you don't need it :)

dismay
21 Sep 2007, 11:20 AM
Hi trbs!

I use your nice extension and many thanks for it.

And I has seen next:

for example this code:


var ds = new Ext.data.Store({
proxy: new Ext.data.PagingMemoryProxy({ "BODY":[{"name":"A"},{"name":"B"},{"name":"C"},{"name":"D"}....}),
reader: new Ext.data.JsonReader({
root: 'BODY',
totalProperty: 'totalCount'
}, [{name: 'name', mapping: 'name', type:'string'}]),
remoteSort: true
});

var cm = new Ext.grid.ColumnModel([{
id: 'name',
header: "Name",
dataIndex: 'name',
width: 500,
sortable:true
}]);

var grid = new Ext.grid.Grid('name_div', {
ds: ds,
cm: cm,
selModel: new Ext.grid.RowSelectionModel({singleSelect:false}),
enableColLock:false,
enableDragDrop:false,
loadMask: true
});

grid.render();

var paging = new Ext.PagingToolbar(grid.getView().getFooterPanel(true), ds, {
pageSize: 25,
displayInfo: true,
displayMsg: 'Displaying queues {0} - {1} of {2}',
emptyMsg: "No queues to display"
});

ds.load({params:{start:0, limit:25}});
now I want create filter prcedure:



ds.filterBy(function(r) {
...
// code somthing like if (...) then { retun true; } else { return false; }
...
});and on page limit 25 from 30 records (1 page = 25 records, 2 page = 5 records), so, this filter procedure will be filtering only 1 (!) page from first 25 records..

how can I bind filterBy procedure in your extensions and call it?

this code not working...


...
Ext.extend(Ext.data.PagingMemoryProxy, Ext.data.MemoryProxy, {
load: function(params, reader, callback, scope, arg) {....}
);
....

Ext.data.PagingMemoryProxy.prototype.filterBy = function(fn, scope){
Ext.data.PagingMemoryProxy.superclass.filterBy.call(this, fn, scope);
...
// giving this.proxy.data[ds.reader.meta.root] , filtering, and return records
...
}
maybe it`s wrong way...?

Thanks

trbs
28 Sep 2007, 3:53 PM
Hi trbs!
maybe it`s wrong way...?

Thanks

Sorry for the late reply: dismay

I think it's an interesting option to add something to the Proxy that will let you bind your own filtering function :)

A config option that will let you do:


proxy: new Ext.ux.data.PagingMemoryProxy(
Ext.exampledata.states,
filter: function(el) {
return el.data['active']==true?true:false;
}
)
Or something like that

Currently the only 'way' to use filtering in the proxy is to do it exactly the same way as you would do with another server call. Add 'filter' and optionally 'filterCol' to your store's .params or .baseParams to filter.

trbs
28 Sep 2007, 4:02 PM
I've know added an extra config option to allow users to use there own customerFilter function.



var cm = new Ext.grid.ColumnModel([{
header: "Short Name", dataIndex: 'abbr', width: 100
}, {
header: "Long Name", dataIndex: 'state', width: 200
}]);

// by default columns are sortable
cm.defaultSortable = true;

// create the Data Store
var ds = new Ext.data.Store({
proxy: new Ext.ux.data.PagingMemoryProxy(Ext.exampledata.states, {
customFilter: function(el) {
return el.data['abbr']=='AL';
}
}),
reader: new Ext.data.ArrayReader({}, [
{name: 'abbr'},
{name: 'state'}
]),
remoteSort: true
});


Will only return the state Alabama in the loaded store.

benwg
6 Oct 2007, 8:01 PM
I have changed the code to add those functions:
1.Use ShellSort to sort the records,old sort is very slow when records over 5000;
2.Buffered the records after loaded from data,and buffered the records and sorted,this will increase the speed when change the page.

trbs
7 Oct 2007, 7:14 AM
I have changed the code to add those functions:
1.Use ShellSort to sort the records,old sort is very slow when records over 5000;
2.Buffered the records after loaded from data,and buffered the records and sorted,this will increase the speed when change the page.

First of all... the Paging Memory Proxy is not really meant for really big record sets... Those are normally better handled by paging or server side mechanisms.

This also goes for buffering... I assumed that the record set is already in memory... so buffering it twice (or even three times) in a set with over 5000 records will consume quite a bit of memory... specially if it buffered the entire data structure and not just pointers to the base/original structure.

For sorting i used the sorting methods that Extjs provides for record Sets, which build upon the standard available sorting functions for JavaScript array's... however i do not seem to find any reference on which kind of sorting function/algorithm is used by javascript:Array.prototype.sort

So i went out and dived a little bit into sorting and javascript and it seems that there's some improvement to be made, but often strongly related to witch type of data is in the array. IE: if you know it will be Int's or String's only you can heavily optimize for that.

Just when i wrote my own very sweet and blazing fast ShellSort algorithm, i discovered that I'm using many (new to) Javascript 1.7 functions and programming techniques which result in that sweet speed. Techniques that cannot be back ported to many of the browsers (like IE7) with very old javascript engines... a big shame really ! :( ... (Javascript 1.7 came about in 2006 and still only firefox and other mozilla/gecko browsers seem to support it)

benwg Are you willing to put your code out here ? So i can review it and possibly put the ShellSort algorithm in the UX as an alternative sorting algorithm. (as my version will be firefox/mozilla only, no opera, safari or ie support)

benwg
8 Oct 2007, 8:26 PM
Thinks for your reply,I am very like Extjs,and want to use it in my project.I add some code to improve the performance of grid.becourse my experience of extjs is limited,so may be have some bug,i put my code in attachment,hope to have help to improve the grid.i buffered the Records after Sorted to increase the speech when change the page index.this method can jump over the sort process,I ever want to sort the base data,but have some difficulty for me.

I'm expecting the suggestion from you.


First of all... the Paging Memory Proxy is not really meant for really big record sets... Those are normally better handled by paging or server side mechanisms.

This also goes for buffering... I assumed that the record set is already in memory... so buffering it twice (or even three times) in a set with over 5000 records will consume quite a bit of memory... specially if it buffered the entire data structure and not just pointers to the base/original structure.

For sorting i used the sorting methods that Extjs provides for record Sets, which build upon the standard available sorting functions for JavaScript array's... however i do not seem to find any reference on which kind of sorting function/algorithm is used by javascript:Array.prototype.sort

So i went out and dived a little bit into sorting and javascript and it seems that there's some improvement to be made, but often strongly related to witch type of data is in the array. IE: if you know it will be Int's or String's only you can heavily optimize for that.

Just when i wrote my own very sweet and blazing fast ShellSort algorithm, i discovered that I'm using many (new to) Javascript 1.7 functions and programming techniques which result in that sweet speed. Techniques that cannot be back ported to many of the browsers (like IE7) with very old javascript engines... a big shame really ! :( ... (Javascript 1.7 came about in 2006 and still only firefox and other mozilla/gecko browsers seem to support it)

benwg Are you willing to put your code out here ? So i can review it and possibly put the ShellSort algorithm in the UX as an alternative sorting algorithm. (as my version will be firefox/mozilla only, no opera, safari or ie support)

pooh
16 Oct 2007, 3:56 AM
Thanks dude... It worked for me...yippeeeeeeeeeeeeeee...:D

trbs
25 Oct 2007, 5:48 AM
Thinks for your reply,I am very like Extjs,and want to use it in my project.I add some code to improve the performance of grid.becourse my experience of extjs is limited,so may be have some bug,i put my code in attachment,hope to have help to improve the grid.i buffered the Records after Sorted to increase the speech when change the page index.this method can jump over the sort process,I ever want to sort the base data,but have some difficulty for me.

I'm expecting the suggestion from you.

Thanks man !
I'll look into it when i can, and update the official js files.

Preston
18 Nov 2007, 7:30 AM
First of all:

trbs, thanks for this cool user extension!
This is exactly what I needed! (I know about all of the arguments about the Use Case for pushing all of the data onto the client at once etc... but in my case this is exactly what I need).

I tried your example and it worked like a charm! :)

One Feature request from my side:
- Making the selected rows "persistent" over page impressions.
Here

trbs
19 Nov 2007, 2:35 AM
I think this is more a request for the grid in generality then specificly for the memory proxy.
Cause this would work just as well over a 'normal' grid with server side paging (i think).

You could start by looking at the columnselection models in Ext and see if you can make those persistent over multiple pages. As well as putting something in the bottom or top bar to make the selected across pages visible to the end user.

Good luck !!

H-care S.r.l.
14 Dec 2007, 6:00 AM
Sorry trbs, are you aware that your code is using methods from JavaScript 1.6 that are not (officially) supported by other browsers than Firefox >= 2.0? In your code I can find:


/* Fix for Opera, which does not seem to include the map function on Array's */

The method map, like filter, is included in JavaScript 1.6. Browsers like Internet Explorer 6 and 7 (that sadly are still the most used on the web) both support JavaScript 1.5 (oh, well, they support ECMA-262 3rd edition, that is quite like JavaScript 1.5).

Regards

Pierpaolo

trbs
14 Dec 2007, 6:19 AM
Sorry trbs, are you aware that your code is using methods from JavaScript 1.6 that are not (officially) supported by other browsers than Firefox >= 2.0? In your code I can find:


/* Fix for Opera, which does not seem to include the map function on Array's */

The method map, like filter, is included in JavaScript 1.6. Browsers like Internet Explorer 6 and 7 (that sadly are still the most used on the web) both support JavaScript 1.5 (oh, well, they support ECMA-262 3rd edition, that is quite like JavaScript 1.5).

Regards

Pierpaolo

[My Opinion]
Yes i know :) that's why i included the fix from the developers.mozilla.org site.

I'm just dead tired of every other browser supporting only the 10 year old javascript specification, so i'm just going ahead using the new javascript and fixing support for older browsers where i can.

I personally think everybody should push forward until company's like microsoft / Opera and Apple wake up and start implementing more recent and very very very usefull new javascript functions.
[/My Opinion]

talshadar
18 Dec 2007, 9:47 AM
Hi. I've been using your paging proxy and it works great for most things. I've been having some major troubles getting it to work with Animals DDView http://extjs.com/forum/showthread.php?p=100328. I've gone through his extension and can't find anything in there that should break it. Which makes me think perhaps the View itself can't work with your proxy correctly.

What's happening is that it loads the first time properly - Page 1 of 8 ... 1 - 30 of 234 ... but as soon as i try to go to a different page it goes crazy. Page 101 or 9 - 31 - 234 of 234. Basically it loses the limits etc. I have no idea how to resolve this.

It's important to my application that I have the drag and drop ability but its equally important that I have paging working as well. Have you tested your Proxy extension with the basic View? Or Animals DDView? Can you give me any suggestions on resolving this issue?

I can definitely post the relevant code - but I thought I'd wait to find out whether it should work with View or not.

Any advice is appreciated.

Matthew

axio
18 Dec 2007, 12:22 PM
Thanks for your work on this. It worked right out of the box for me and solved the exact problem I had. :)

trbs
18 Dec 2007, 3:13 PM
Hi. I've been using your paging proxy and it works great for most things. I've been having some major troubles getting it to work with Animals DDView http://extjs.com/forum/showthread.php?p=100328. I've gone through his extension and can't find anything in there that should break it. Which makes me think perhaps the View itself can't work with your proxy correctly.

What's happening is that it loads the first time properly - Page 1 of 8 ... 1 - 30 of 234 ... but as soon as i try to go to a different page it goes crazy. Page 101 or 9 - 31 - 234 of 234. Basically it loses the limits etc. I have no idea how to resolve this.

It's important to my application that I have the drag and drop ability but its equally important that I have paging working as well. Have you tested your Proxy extension with the basic View? Or Animals DDView? Can you give me any suggestions on resolving this issue?

I can definitely post the relevant code - but I thought I'd wait to find out whether it should work with View or not.

Any advice is appreciated.

Matthew

Please do post a working demo of your problem online, that will help us help you tracking down this problem a _lot_ faster.

I have never played with DDView myself, but i would love to see in action.

As it sounds it could be a problem with the MemoryProxy (corner case?) as Animal says his DDView should basically work with anything that is an Ext store.


Basically, anything that is underpinned by an Ext.data.Store of Ext.data.Records can easily handle fully automatic DnD.

Anyways please put something online and i'll try to take a look at it as fast as i can.

Regards,
trbs

Shmoo
18 Dec 2007, 4:58 PM
Very great work indeed!!! It solved my problem right out of the box too! =D>

H-care S.r.l.
19 Dec 2007, 2:33 AM
[My Opinion]
Yes i know :) that's why i included the fix from the developers.mozilla.org site.

I'm just dead tired of every other browser supporting only the 10 year old javascript specification, so i'm just going ahead using the new javascript and fixing support for older browsers where i can.

I personally think everybody should push forward until company's like microsoft / Opera and Apple wake up and start implementing more recent and very very very usefull new javascript functions.
[/My Opinion]

Your opinion is like my opinion. But map, filter and forEach methods are not a real problem for us, 'cause you can redefine them in a easy way (like you did).
The problem is the language itself and new features that JS 1.7 (and up) I would like to use (like array comprehensions, generators, iterators, etc.).

My initial question was only about your comment...only to know if you were doing thing in a expected way :)

Thank you very much,
Pierpaolo

talshadar
19 Dec 2007, 6:58 AM
Unfortunately I can't put a working version online anywhere because it's for an internal company application. I can post the code but that's it :-(

I haven't bothered to include the declarations for dsImages, dsImageThumbs, imageColModel or imageRowSel. I load the PagingMemoryProxy and the datastore once they've selected a category from the tree.

Existing Issues:
1)Initially the paging toolbar was attached to the parent element of the view - I had to put an additional layer (layout and panel) for the view because otherwise the toolbar attached itself to the main borderlayout - and was visible on both tabs. But this results in wierd layout issues - where the toolbar sometimes shows up - sometimes doesn't. It's often hidden by the section with the tabs unless I can scroll it. So it's not the perfect solution.

2) This is the biggest issue I'm having. When the proxy and the datastore are first loaded - everything works great. It gives me the first 30 images - for page 1 for the total pages as well as the total image count. But as soon as I go to any other page it loses what it's doing. If I go to the second page it says Page 101 of 8 ... 0301 - 030204 of 234 Records. And it loads all the images left - 31 to 234.

I've tried everything I can think of and can not resolve this issue. I only have 2 more days to finish this project and these are the only 2 issues left. The paging obviously is the most important with the layout issue being a very close second.

I would appreciate any help or advice I can get!

Thanks in advance!

Matthew





// Define the search grid
imagesGrid = new Ext.grid.EditorGrid("imagesDiv",{
ds:dsImages,
autoExpandColumn:"Filename",
cm:imageColModel,
loadMask: {msg: "Loading Images..."},
selModel:imageRowSel,
enableColLock: true,
autoCreate: true,
stripeRows: true
});

imagesGrid.render();

var gridHead = imagesGrid.getView().getHeaderPanel(true);
var tb = new Ext.Toolbar(gridHead, [
"-",
{
text: " Save",
icon: "./images/save.gif",
cls: "x-btn-text-icon",
tooltip: "<b>Save</b><br/>Saves changes made to the Images",
handler : btnSaveChanges_OnClick
}
]);

var gridFoot = imagesGrid.getView().getFooterPanel(true);
// add a paging toolbar to the grid's footer
var paging = new Ext.PagingToolbar(gridFoot, dsImages, {
pageSize: 30,
displayInfo: true,
displayMsg: 'Rows {0} - {1} of {2}',
emptyMsg: "No records to display"
});

Tree = Ext.tree;

imageListLayout = new Ext.BorderLayout('imageListLayout', {
west: {
initialSize:200,
split:true,
autoCreate:true,
fitToFrame:true,
titlebar:true,
autoScroll:true
},
center: {
initialSize:600,
titlebar:true,
autoCreate:true,
fitToFrame:true,
autoScroll:true
}
});

imagesList = imageListLayout.add("center", new Ext.GridPanel(imagesGrid, {
title:"Image List",
initialSize:600,
autoCreate:true,
fitToFrame:false,
autoScroll:true
}) );

//image thumbnail view needs a parent nested layout
imageThumbsLayout = new Ext.BorderLayout('imageThumbLayout', {
center: {
initialSize:400,
titlebar:false,
autoCreate:true,
fitToFrame:false,
autoScroll:true
}
});

imagesThmbs = imageThumbsLayout.add('center', new Ext.ContentPanel('imageThmbsDiv', {
initialSize:400,
fitToFrame:false,
autoScroll:true,
autoCreate:true
}));

imgThumbPanel = new Ext.NestedLayoutPanel(imageThumbsLayout, {title: "Image Thumbnails", fitToFrame: true, autoCreate:true, autoScroll:true } );

imageListLayout.beginUpdate();
imageListLayout.add("center",imgThumbPanel);
imageListLayout.endUpdate();

//tried several versions for this as well
// imgBody = imgThumbPanel.getEl();
imgBody = imagesThmbs.getEl();

// now setup the templates etc required to show thumbnails of the images

var qtipTpl = new Ext.Template(
'<div id="{URL}" class="image-tip"><img src="{URL}" align="left">'+
'<b>Image Name:</b>' +
'<span>{Title}</span>' +
'<b>Size:</b>' +
'<span>{sizeString}</span></div>'
);
qtipTpl.compile();

vwImageThmbs = new Ext.ux.DDView(imgBody, '<div id="{imageLink}" class="thumb-wrap"><div class="thumb"><img src="{URL}" class="thumb-img"></div><span>{shortName}</span></div>',
{
animate: true,
autoCreate:true,
autoScroll:true,
fitToFrame: true,
multiSelect: true,
selectedClass: "x-view-selected",
store: dsImageThumbs,
allowDup : false,
allowCopy : false,
forceFit: true,
dragGroup : 'treeDropGroup',
dropGroup : 'viewDragGroup'
}
);

//as you can see I've tried several versions of creating the footer
viewThumbsFooter = Ext.get(vwImageThmbs.el.dom.parentNode).createChild({tag: "div", cls:"viewFooter"});
// viewThumbsFooter = imgThumbPanel.getEl().createChild({tag: "div", cls:"viewFooter"});
// viewThumbsFooter = Ext.get(vwImageThmbs).createChild({tag: "div", cls:"viewFooter"});

vwImageThmbs.prepareData = function(data){
data.shortName = data.Title.ellipse(15);;
data.sizeString = (Math.round(((data.Size*10) / 1024))/10) + " KB";
data.qtip = new String(qtipTpl.applyTemplate(data));
return data;
};

thumbsPagingToolbar = new Ext.PagingToolbar(viewThumbsFooter, dsImageThumbs, {
pageSize: "30",
displayInfo: true,
displayMsg: 'Rows {0} - {1} of {2}',
emptyMsg: "No records to display"
});

vwImageThmbs.addListener('dblClick', vwImage_OnDblClick);

categoryTreePanel = imageListLayout.add('west', new Ext.ContentPanel('categoriesDiv', {
title:'Image Categories',
fitToFrame:true,
autoScroll:true
}));

treeEl = categoryTreePanel.getEl().createChild({tag:"div", id:"categoryFolders"});

treeCategory = new Ext.tree.TreePanel(treeEl, {
/ animate:false,
loader: new Ext.tree.TreeLoader({
dataUrl:'BuildTree.aspx'
}),
enableDD:true,
ddGroup: 'treeDropGroup',
containerScroll: true
});

//add listener for right click context menu
treeCategory.addListener('contextmenu',treeCategoryContextMenu_onRightClick);

// set the root node
treeRoot = new Ext.tree.AsyncTreeNode({
text: 'Image Categories',
allowDrag:false,
allowDrop:false,
id:'0000'
});

treeCategory.setRootNode(treeRoot);
treeCategory.addListener("click", node_OnClick);

// render the tree
treeCategory.render();
treeRoot.expand();

// add an inline editor for the nodes
tCategoryEditor = new Ext.tree.TreeEditor(treeCategory, {
allowBlank:false,
blankText:'A name is required',
selectOnFocus:true
});

//add 2 listeners - 1 for finished edit and one before start to verify permisions
tCategoryEditor.addListener('beforestartedit', treeCategoryEdit_BeforeEdit);
tCategoryEditor.addListener('complete', treeCategoryEdit_Complete);

//add listeners for drag/drop
treeCategory.addListener('beforenodedrop',treeCategory_BeforeDrop);
treeCategory.addListener('nodedrop',treeCategory_AfterDrop);

//now load everything into main layout

layout = new Ext.BorderLayout(document.body, {
center: {
autoScroll:true,
tabPosition: "top",
fitToFrame:true,
autoCreate:true
}
}
);

// Build our content
imagesPanel = new Ext.NestedLayoutPanel(imageListLayout, {title: "Image List"} );

layout.beginUpdate();
layout.add("center", imagesPanel );
layout.endUpdate();

trbs
21 Dec 2007, 8:23 AM
Unfortunately I can't put a working version online anywhere because it's for an internal company application. I can post the code but that's it :-(

I haven't bothered to include the declarations for dsImages, dsImageThumbs, imageColModel or imageRowSel. I load the PagingMemoryProxy and the datastore once they've selected a category from the tree.

Existing Issues:
1)Initially the paging toolbar was attached to the parent element of the view - I had to put an additional layer (layout and panel) for the view because otherwise the toolbar attached itself to the main borderlayout - and was visible on both tabs. But this results in wierd layout issues - where the toolbar sometimes shows up - sometimes doesn't. It's often hidden by the section with the tabs unless I can scroll it. So it's not the perfect solution.

2) This is the biggest issue I'm having. When the proxy and the datastore are first loaded - everything works great. It gives me the first 30 images - for page 1 for the total pages as well as the total image count. But as soon as I go to any other page it loses what it's doing. If I go to the second page it says Page 101 of 8 ... 0301 - 030204 of 234 Records. And it loads all the images left - 31 to 234.

I've tried everything I can think of and can not resolve this issue. I only have 2 more days to finish this project and these are the only 2 issues left. The paging obviously is the most important with the layout issue being a very close second.

I would appreciate any help or advice I can get!

Thanks in advance!

Matthew





// Define the search grid
imagesGrid = new Ext.grid.EditorGrid("imagesDiv",{
ds:dsImages,
autoExpandColumn:"Filename",
cm:imageColModel,
loadMask: {msg: "Loading Images..."},
selModel:imageRowSel,
enableColLock: true,
autoCreate: true,
stripeRows: true
});

imagesGrid.render();

var gridHead = imagesGrid.getView().getHeaderPanel(true);
var tb = new Ext.Toolbar(gridHead, [
"-",
{
text: "&nbsp;Save",
icon: "./images/save.gif",
cls: "x-btn-text-icon",
tooltip: "<b>Save</b><br/>Saves changes made to the Images",
handler : btnSaveChanges_OnClick
}
]);

var gridFoot = imagesGrid.getView().getFooterPanel(true);
// add a paging toolbar to the grid's footer
var paging = new Ext.PagingToolbar(gridFoot, dsImages, {
pageSize: 30,
displayInfo: true,
displayMsg: 'Rows {0} - {1} of {2}',
emptyMsg: "No records to display"
});

Tree = Ext.tree;

imageListLayout = new Ext.BorderLayout('imageListLayout', {
west: {
initialSize:200,
split:true,
autoCreate:true,
fitToFrame:true,
titlebar:true,
autoScroll:true
},
center: {
initialSize:600,
titlebar:true,
autoCreate:true,
fitToFrame:true,
autoScroll:true
}
});

imagesList = imageListLayout.add("center", new Ext.GridPanel(imagesGrid, {
title:"Image List",
initialSize:600,
autoCreate:true,
fitToFrame:false,
autoScroll:true
}) );

//image thumbnail view needs a parent nested layout
imageThumbsLayout = new Ext.BorderLayout('imageThumbLayout', {
center: {
initialSize:400,
titlebar:false,
autoCreate:true,
fitToFrame:false,
autoScroll:true
}
});

imagesThmbs = imageThumbsLayout.add('center', new Ext.ContentPanel('imageThmbsDiv', {
initialSize:400,
fitToFrame:false,
autoScroll:true,
autoCreate:true
}));

imgThumbPanel = new Ext.NestedLayoutPanel(imageThumbsLayout, {title: "Image Thumbnails", fitToFrame: true, autoCreate:true, autoScroll:true } );

imageListLayout.beginUpdate();
imageListLayout.add("center",imgThumbPanel);
imageListLayout.endUpdate();

//tried several versions for this as well
// imgBody = imgThumbPanel.getEl();
imgBody = imagesThmbs.getEl();

// now setup the templates etc required to show thumbnails of the images

var qtipTpl = new Ext.Template(
'<div id="{URL}" class="image-tip"><img src="{URL}" align="left">'+
'<b>Image Name:</b>' +
'<span>{Title}</span>' +
'<b>Size:</b>' +
'<span>{sizeString}</span></div>'
);
qtipTpl.compile();

vwImageThmbs = new Ext.ux.DDView(imgBody, '<div id="{imageLink}" class="thumb-wrap"><div class="thumb"><img src="{URL}" class="thumb-img"></div><span>{shortName}</span></div>',
{
animate: true,
autoCreate:true,
autoScroll:true,
fitToFrame: true,
multiSelect: true,
selectedClass: "x-view-selected",
store: dsImageThumbs,
allowDup : false,
allowCopy : false,
forceFit: true,
dragGroup : 'treeDropGroup',
dropGroup : 'viewDragGroup'
}
);

//as you can see I've tried several versions of creating the footer
viewThumbsFooter = Ext.get(vwImageThmbs.el.dom.parentNode).createChild({tag: "div", cls:"viewFooter"});
// viewThumbsFooter = imgThumbPanel.getEl().createChild({tag: "div", cls:"viewFooter"});
// viewThumbsFooter = Ext.get(vwImageThmbs).createChild({tag: "div", cls:"viewFooter"});

vwImageThmbs.prepareData = function(data){
data.shortName = data.Title.ellipse(15);;
data.sizeString = (Math.round(((data.Size*10) / 1024))/10) + " KB";
data.qtip = new String(qtipTpl.applyTemplate(data));
return data;
};

thumbsPagingToolbar = new Ext.PagingToolbar(viewThumbsFooter, dsImageThumbs, {
pageSize: "30",
displayInfo: true,
displayMsg: 'Rows {0} - {1} of {2}',
emptyMsg: "No records to display"
});

vwImageThmbs.addListener('dblClick', vwImage_OnDblClick);

categoryTreePanel = imageListLayout.add('west', new Ext.ContentPanel('categoriesDiv', {
title:'Image Categories',
fitToFrame:true,
autoScroll:true
}));

treeEl = categoryTreePanel.getEl().createChild({tag:"div", id:"categoryFolders"});

treeCategory = new Ext.tree.TreePanel(treeEl, {
/ animate:false,
loader: new Ext.tree.TreeLoader({
dataUrl:'BuildTree.aspx'
}),
enableDD:true,
ddGroup: 'treeDropGroup',
containerScroll: true
});

//add listener for right click context menu
treeCategory.addListener('contextmenu',treeCategoryContextMenu_onRightClick);

// set the root node
treeRoot = new Ext.tree.AsyncTreeNode({
text: 'Image Categories',
allowDrag:false,
allowDrop:false,
id:'0000'
});

treeCategory.setRootNode(treeRoot);
treeCategory.addListener("click", node_OnClick);

// render the tree
treeCategory.render();
treeRoot.expand();

// add an inline editor for the nodes
tCategoryEditor = new Ext.tree.TreeEditor(treeCategory, {
allowBlank:false,
blankText:'A name is required',
selectOnFocus:true
});

//add 2 listeners - 1 for finished edit and one before start to verify permisions
tCategoryEditor.addListener('beforestartedit', treeCategoryEdit_BeforeEdit);
tCategoryEditor.addListener('complete', treeCategoryEdit_Complete);

//add listeners for drag/drop
treeCategory.addListener('beforenodedrop',treeCategory_BeforeDrop);
treeCategory.addListener('nodedrop',treeCategory_AfterDrop);

//now load everything into main layout

layout = new Ext.BorderLayout(document.body, {
center: {
autoScroll:true,
tabPosition: "top",
fitToFrame:true,
autoCreate:true
}
}
);

// Build our content
imagesPanel = new Ext.NestedLayoutPanel(imageListLayout, {title: "Image List"} );

layout.beginUpdate();
layout.add("center", imagesPanel );
layout.endUpdate();



Okey, hope you figure it out before then.

It's too bad that i do not have the time to start writing up a working example from the code you posted... With my own projects / X-Mass and New Years etc. there just so little time in a day ;)

From what you write, i would try with my favorite tool. Firebug, and add breakpoints to the code too figure out why those numbers are all over the place.

One thing tho... if you leave the memoryproxy out and use a normally proxy for the paging grid, does it then do the same thing ? or does it then work correctly.

And of course, a Marry X-Mass and Happy New Year to all my Ext-Friends ;) !!!

talshadar
21 Dec 2007, 10:18 AM
I tracked down the paging error. It was how I was declaring the value for the records per page:

This is what I had:


thumbsPagingToolbar = new Ext.PagingToolbar(viewThumbsFooter, dsImageThumbs, {
pageSize: "30",
displayInfo: true,
displayMsg: 'Rows {0} - {1} of {2}',
emptyMsg: "No records to display"
});


I removed the quotes around the pageSize:


thumbsPagingToolbar = new Ext.PagingToolbar(viewThumbsFooter, dsImageThumbs, {
pageSize: 30,
displayInfo: true,
displayMsg: 'Rows {0} - {1} of {2}',
emptyMsg: "No records to display"
});


And boom it works!!! So yay! My holiday is starting off great!!

bean
27 Dec 2007, 2:56 PM
trbs, does your extension work with 2.0? Having a bit of trouble implementing it and just want to make sure it is possible. Thanks.

trbs
27 Dec 2007, 3:17 PM
trbs, does your extension work with 2.0? Having a bit of trouble implementing it and just want to make sure it is possible. Thanks.

Yeah it should work fine in Ext2.0, it's used in one of the locale examples.

http://extjs.com/deploy/dev/examples/locale/multi-form.html

If there any bugs with it and 2.0 please post here and i'll try to fix them.

bean
31 Dec 2007, 3:04 PM
Yeah it should work fine in Ext2.0, it's used in one of the locale examples.

http://extjs.com/deploy/dev/examples/locale/multi-form.html

If there any bugs with it and 2.0 please post here and i'll try to fix them.
Thanks, I finally got it working!

For anybody who is trying to implement trbs's extension with JSON and Ext2.0, try using this as a base (I dont know if this the most efficient setup, but it works :) )



Ext.onReady(function(){

var js = new Ext.data.JsonStore({
url: 'Orders.aspx?action=getGetOrders',
root: 'order',
fields: [{name:'orderID', type: 'int'},
{name:'orderDate', type: 'date'},
{name:'dateSubmitted', type: 'date'},
{name:'orderType', type:'string'},
{name:'customerid', type:'int'},
{name:'totalamount', type:'float'}
]
});

js.on('load', function()
{
var ds = new Ext.data.Store({
proxy: new Ext.ux.data.PagingMemoryProxy(js.reader.jsonData),
reader: js.reader,
remoteSort: true
});

var myGrid = new Ext.grid.GridPanel
({
el:'content',
store: ds,
columns:
[
{header: 'Order ID', width: 125, sortable: true, dataIndex: 'orderID'},
{header: 'Order Date', width: 125, sortable: true, dataIndex: 'orderDate'},
{header: 'Date Submitted', width: 125, sortable: true, dataIndex: 'dateSubmitted'},
{header: 'Order Type', width: 125, sortable: true, dataIndex: 'orderType'},
{header: 'Customer ID', width: 125, sortable: true, dataIndex: 'customerid'},
{header: 'Total Amount', width: 125, sortable: true, dataIndex: 'totalamount'},
],
title: 'Order Detail',
width: 500,
loadMask: true,
viewConfig:
{
forceFit:true,
enableRowBody:true,
showPreview:true
},
bbar: new Ext.PagingToolbar
({
pageSize: 5,
emptyMsg: "No topics to display",
store: ds,
displayInfo: true,
displayMsg: 'Displaying Orders {0} - {1} of {2}',
emptyMsg: "No orders to display"
})
});

myGrid.render();
ds.load({params:{start:0, limit:5}});

});// js.onload
js.load();
}); // onReady

arya009
17 Jan 2008, 2:23 AM
Thanks, I finally got it working!

For anybody who is trying to implement trbs's extension with JSON and Ext2.0, try using this as a base (I dont know if this the most efficient setup, but it works :) )



Ext.onReady(function(){

var js = new Ext.data.JsonStore({
url: 'Orders.aspx?action=getGetOrders',
root: 'order',
fields: [{name:'orderID', type: 'int'},
{name:'orderDate', type: 'date'},
{name:'dateSubmitted', type: 'date'},
{name:'orderType', type:'string'},
{name:'customerid', type:'int'},
{name:'totalamount', type:'float'}
]
});

js.on('load', function()
{
var ds = new Ext.data.Store({
proxy: new Ext.ux.data.PagingMemoryProxy(js.reader.jsonData),
reader: js.reader,
remoteSort: true
});

var myGrid = new Ext.grid.GridPanel
({
el:'content',
store: ds,
columns:
[
{header: 'Order ID', width: 125, sortable: true, dataIndex: 'orderID'},
{header: 'Order Date', width: 125, sortable: true, dataIndex: 'orderDate'},
{header: 'Date Submitted', width: 125, sortable: true, dataIndex: 'dateSubmitted'},
{header: 'Order Type', width: 125, sortable: true, dataIndex: 'orderType'},
{header: 'Customer ID', width: 125, sortable: true, dataIndex: 'customerid'},
{header: 'Total Amount', width: 125, sortable: true, dataIndex: 'totalamount'},
],
title: 'Order Detail',
width: 500,
loadMask: true,
viewConfig:
{
forceFit:true,
enableRowBody:true,
showPreview:true
},
bbar: new Ext.PagingToolbar
({
pageSize: 5,
emptyMsg: "No topics to display",
store: ds,
displayInfo: true,
displayMsg: 'Displaying Orders {0} - {1} of {2}',
emptyMsg: "No orders to display"
})
});

myGrid.render();
ds.load({params:{start:0, limit:5}});

});// js.onload
js.load();
}); // onReady


=D>=D>=D>

that was excellent tip...it solved 2 of my problems Paging and sorting ;)

kvs
22 Jan 2008, 11:23 PM
Hi trbs.
You've done a very nice work indeed. Thank you. Here is a one more example of using your extension. I need to execute a very long running database query returning a bulk of data. Without your extension when i change page i need to make a round trip to server and wait for database to execute time consuming query again. Using server cache for the query result is not applicable for me because there may be a hundreds of query users. With your extension i can execute query once and do paging, filtering, sorting at a client side. But there is still speed problem. A query can return a thousand rows of data. When i sort data i get considerable delays when i do paging. I've looked thru the source code and i've found out that every time page is changing you execute readRecords, filter and sort even if neither data nor filter/sort conditions wasn't changed.
Here my proposals:
Add a config parameter (say) refresh. If refresh == true then execute readRecords, filter and sort every time function load is executing as it goes now, else execute readRecords only once (when function load is executing for the first time), execute filter and sort only if filter/sort conditions have changed.

arya009
23 Jan 2008, 3:32 AM
Yes i have the same problem too...

My grid is having more than 100,000 records and it takes too much time to load...

hendricd
23 Jan 2008, 10:51 AM
Your welcome to try this variation. It uses a shellShort instead (but only if the sort parameters have changes since the last paging operation.

Recent Changes in bold.


/**
* Ext.ux.data.BufferedPagingMemoryProxy .js
*
* A proxy for local / in-browser data structures
* supports paging / sorting / filtering / etc
*
* @file Ext.ux.BufferedPagingMemoryProxy.js
* @author : Doug Hendricks
*
* A modified version of Ext.ux.data.PagingMemoryProxy.js
* by: Ido Sebastiaan Bas van Oostveen
*
*/

//Adds the requisite Array.prototype filter
Ext.applyIf(Array.prototype, {
filter: function(iter, scope) {
var results = [];
Ext.each(this, function(value, index) {
if (iter.call(scope, value, index)) results.push(value);
});
return results;
});

Ext.ux.data.BufferedPagingMemoryProxy = function(data,config) {
Ext.ux.data.BufferedPagingMemoryProxy.superclass.constructor.call(this);
this.data = data||[];

Ext.apply(this, config);
};

Ext.extend(Ext.ux.data.BufferedPagingMemoryProxy, Ext.data.MemoryProxy, {
filter: null,

sortField : null,
sortDir : null,
lastFilters : {using:false,on:0},
lastSorts : {on:false,dir:null},
clear : function(){ this.data = []; },
load : function(params, reader, callback, scope, arg) {

//Normalize to config
params || (params = {});

//params take precedence
var sorts = {on:params.sort || this.sortField || this.lastSorts.on
, dir : params.dir || this.sortDir || this.lastSorts.dir }

,filter = {using: params.filter
,on: params.filterCol
}

,config = Ext.apply( {}, params,
{ filters: filter
,filterCol: 0
,sorts : sorts
,start:undefined
,limit:undefined
})
,result
,success = true
,_diff = function(src, target){

if(!src || !target)return true;
var a;
for(a in src){
if(src[a] !== target[a])return true;
}
for( a in target){
if(target[a] !== src[a])return true;
}
return false;

};


try {

var data;
var filterChange = _diff(this.lastFilters , config.filters);
var sortChange = _diff(this.lastSorts , config.sorts);

if(this.data.buffered && !sortChange){

if(this.data.buffered.filtered && filterChange ){
result = reader.readRecords(this.data);
sortChange = true;
}else
{ result = Ext.apply({records: this.data.buffered.records} ,
{
_sorts :this.data._sorts,
filtered :this.data.buffered.filtered
});
}
} else {
result = reader.readRecords(this.data);
filterChange = true;
}


sortChange = sortChange || _diff(result._sorts , config.sorts);

if(sortChange ){

if(config.sorts.on)
{

var dir = String(config.sorts.dir).toUpperCase() == "DESC" ? -1 : 1
,st = reader.recordType.getField(config.sorts.on).sortType
,data = [].concat(result.records)
,shellSort = function(array, begin, end){

for (var step = end >> 1; step > 0; step >>= 1)
{
for (var i = 0; i < step; ++i)
{
for (var j = i + step; j < end; j += step)
{
var k = j, value = array[j];
while (k >= step && (array[k - step].data[config.sorts.on]==value.data[config.sorts.on] ? 0 : array[k - step].data[config.sorts.on]<value.data[config.sorts.on] ? -1 : 1) * dir > 0)
{
array[k] = array[k - step];
k -= step;
}
array[k] = value;
}
}
}
};
shellSort(data,0,data.length);

}

this.sortField = config.sorts.on; //save last sort values
this.sortDir = config.sorts.dir;

}

if(data)result.records = data;
result.totalRecords= result.records.length;

// filtering
if(filterChange) {

if(config.filters.using){
result.filtered = true;
if (typeof config.filters.using == 'function') {
result.records = result.records.filter(config.filters.using);

} else {
result.records = result.records.filter(function(el){
if (typeof(el)=="object"){
var att = config.filters.on || 0;
return String(el.data[att]).match(config.filters.using)?true:false;
} else {
return String(el).match(config.filters.using)?true:false;
}
});

}
}
}

result.totalRecords = result.records.length;

Ext.apply( this.data,
{
_sorts :this.lastSorts = config.sorts
,buffered :result
});

this.lastFilters = config.filters;

var output = result;

// paging (use undefined cause start can also be 0 (thus false))
if (config.start!==undefined && config.limit!==undefined) {
output= Ext.apply({}
,{records : [].concat(result.records).slice(config.start, config.start+config.limit)}
,result);

}
} catch(e) {
this.fireEvent("loadexception", this, arg, null, e);

success = false;
}

callback.call(scope, output, arg, success);
}
});

trbs
24 Jan 2008, 5:43 AM
thanks guys :)
i never intended this to be used with large datasets, but it's clear you guys have a real need for it.

reading from the posts here i suggest the following:
- decouple sorting algoritme from the pagingproxy. (so you can use whatever algoritme you want)
- add extra options like; the refresh option, cache sorting between requests, etc

possible extra features:
- implement partial / background loading.
- prefetching pages in memory.

thinks to check:
- make sure the dataset is buffered only onces in memory. (if you have very large in memory datasets you don't want to have X copies lying around)

Manishs_s
1 Feb 2008, 11:42 AM
Great Man!

Nice paging script...I got implemented in sigle shot.
Hats off to you!

larsthor
12 Feb 2008, 2:21 AM
Hello!

I am new to ExtJS and are tinkering around with it to learn more. In your example with PagingMemoryProxy in multi-lang.js it seems like the paging works when dealing with an array (like the monthArray).

Is it also possible to use paging with a local static XML file? And if so, could you steer me in the right direction how to set that up? With an example, maybe?

I am aware with serverside code sending data etc for paging, but I would like to handle paging with a local XML file. Is that possible with your extention?

Thanks

Lars

DAddYE
25 Mar 2008, 11:30 AM
Hello!

thanks for your great plugin, now I've some like this



var ds = new Ext.data.Store({
reader: new Ext.data.JsonReader({root: 'Accounts', id: 'id', totalProperty: 'Total'}, accounts),
proxy: new Ext.ux.data.PagingMemoryProxy(new Ext.data.HttpProxy({url: '/myurl'})),
});


How I can use your ext with my code?

DAddYE
26 Mar 2008, 2:16 AM
Is possible also show an example with a clientside search?

DAddYE
26 Mar 2008, 3:19 AM
trbs

I've just have a good working live search with your ext.

You need (if possible) change your function in this:



// filtering
if (this.customFilter!=null) {
result.records = result.records.filter(this.customFilter);
result.totalRecords = result.records.length;
} else if (params.filter!==undefined && params.items!==undefined) {
result.records = result.records.filter(function(r){
var items = params.items;
valueArr = params.filter.split(/\ +/);
for (var j=0; j<valueArr.length; j++) {
re = new RegExp(Ext.escapeRe(valueArr[j]), "i");
keep = false;
for (var i=0; i < items.length; i++) {
if (re.test(r.data[items[i].name])==true){
keep=true;
}
}
if (!keep){
return false;
}
}
return true;
});
result.totalRecords = result.records.length;
}


and this work super very well with this live search:



//
// Created by Davide D'Agostino on 2008-01-19.
// Copyright 2008 Lipsiasoft s.r.l. All rights reserved.
//

Ext.app.SearchField = Ext.extend(Ext.form.TwinTriggerField, {
initComponent : function(){
Ext.app.SearchField.superclass.initComponent.call(this);
this.on('keypress', function(f, e){
this.onTrigger2Click();
}, this);
},

fireKey : function(e){
Ext.app.SearchField.superclass.fireKey.call(this,e);
if(!e.isSpecialKey()){
this.fireEvent("keypress", this, e);
}
},

//validationEvent:false,
//validateOnBlur:false,
trigger1Class:'x-form-clear-trigger',
trigger2Class:'x-form-search-trigger',
width:180,
hasSearch : false,
paramName : 'filter',
items:[],


onTrigger1Click : function(){
if(this.hasSearch){
this.el.dom.value = '';
this.store.baseParams = this.store.baseParams || {};
this.store.baseParams[this.paramName] = '';
this.store.load({params:{start:0, limit:10}});
this.hasSearch = false;
}
},

onTrigger2Click : function(){
var v = this.getRawValue();
if(v.length < 1){
this.onTrigger1Click();
return;
}
this.store.baseParams = this.store.baseParams || {};
this.store.baseParams[this.paramName] = v;
this.store.baseParams['items'] = this.items;
this.store.load({params:{start:0, limit:10}});
this.hasSearch = true;
}
});

ajay
2 Apr 2008, 4:13 AM
Hi,

I am relatively new to ExtJs. We are using your PagingMemoryProxy but have not been able to get it work. All the records show on the first page only. We appreciate any help.

Thanks.




/*
* Extjs Drive In Gride javaScript
* Walter Barnie
* 7 March 2008
*
*/
var driveInGrid = function() {
var ds;
var grid;
var cm;
var paging;

function setupDataSource(){
ds = new Ext.data.JsonStore({
proxy: new Ext.ux.data.PagingMemoryProxy('rows'),
url: 'DriveInListingAction.do',
id: 'getAppraisalId',
root: 'rows',
fields: ['getAppraisalNumber',
'getAppraisalId',
'getVehicleModel',
'getDamageDescription',
'getAppraisalType',
'getTotalLoss',
'getClaimantName',
'getHomePhone',
'getAppraisalStatusChangeDate',
'getClaimNumber',
'getVehicleRegistration',
'getVehicleIdNumber',
'getCompanyWrittenFor',
'getNumberDays'
]
});
var filterValue = Ext.get('filter').getValue();
//ds.load({params:{filter: filterValue, start:0, limit:25}});
ds.load({params:{start:0, limit:5, userAction:'list'}});
}

function getColumnModel() {
if(!cm) {
cm = new Ext.grid.ColumnModel([
{
header: 'Appraisal #',
id: 'appraisalId',
name: 'appraisalId',
dataIndex: 'getAppraisalNumber',
sortable: 'true'
},
{
header: 'Vehicle Description',
id: 'vehicleDescription',
name: 'vehicleDescription',
sortable: 'true',
dataIndex: 'getVehicleModel'
},
{
header: 'Damage Description',
id: 'damageDescription',
name: 'damageDescription',
sortable: 'true',
dataIndex: 'getDamageDescription'
},
{
header: 'Appraisal Type',
id: 'appraisalType',
name: 'appraisalType',
sortable: 'true',
dataIndex: 'getAppraisalType'
},
{
header: 'Total Loss',
id: 'totalLoss',
name: 'totalLoss',
sortable: 'true',
dataIndex: 'getTotalLoss'
},
{
header: 'Claimant Name',
id: 'claimantName',
name: 'claimantName',
sortable: 'true',
dataIndex: 'getClaimantName'
},
{
header: 'Contact#',
id: 'contactNumber',
name: 'contactNumber',
sortable: 'true',
renderer: renderPhone,
dataIndex: 'getHomePhone'
},
{
header: 'Status Date',
id: 'statusDate',
name: 'statusDate',
sortable: 'true',
dataIndex: 'getAppraisalStatusChangeDate'
},
{
header: 'Clam#',
id: 'claimNumber',
name: 'claimNumber',
sortable: 'true',
dataIndex: 'getClaimNumber'
},
{
header: 'Plate#',
id: 'plateNumber',
name: 'plateNumber',
sortable: 'true',
dataIndex: 'getVehicleRegistration'
},
{
header: 'VIN last 6',
id: 'vinNumber',
name: 'vinNumber',
sortable: 'true',
dataIndex: 'getVehicleIdNumber'
},
{
header: 'Company Written For',
id: 'companyWrittenFor',
name: 'companyWrittenFor',
sortable: 'true',
dataIndex: 'getCompanyWrittenFor'
}
]);
}
return cm;
}

function buildGrid() {
grid = new Ext.grid.Grid('driveInGrid', {
ds: ds,
cm: getColumnModel(),
autoWidth: true,
height: 300,
trackMouseOver: true,
enableRowHeightSync: true,
autoHeight: true,
selModel: new Ext.grid.RowSelectionModel({singleSelect:false}),
enableColLock:false,
enableDragDrop:false,
loadMask: true
});

grid.getView().getRowClass = function(row, index) {
if (row.data.getNumberDays > 44) {
return 'fortyFiveDays';
}
};
grid.render();

paging = new Ext.PagingToolbar(grid.getView().getFooterPanel(true), ds, {
pageSize: 5,
displayInfo: true,
displayMsg: 'Displaying items {0} - {1} of {2}',
emptyMsg: "No results to display"
});
}

function setupButtons() {
Ext.get('selectAll').on('click', function(){
grid.getSelectionModel().selectAll();
});

if(Ext.get('downLoad')) {
Ext.get('downLoad').on('click', function(){
Ext.MessageBox.alert('Status', 'Not Implemented Yet.');
});
}

if(Ext.get('configuration')) {
Ext.get('configuration').on('click', function(){
Ext.MessageBox.alert('Status', 'Not Implemented Yet.');
});
}

if(Ext.get('delete')) {
Ext.get('delete').on('click', function(){
if (grid.getSelectionModel().getCount() === 0){
Ext.MessageBox.alert('Error', 'There must be at least 1 item selected for processing.' );
}
else
{
Ext.MessageBox.confirm('Delete Drive In Assigments', 'Are you sure you want to delete these rows?', function(btn) {
if(btn == 'yes') {
var selected = grid.getSelectionModel().getSelections();
// get the first key
var keyValues = selected[0].get('getAppraisalId');
// now concatenate the rest
for(i = 1; i < selected.length; i++) {
keyValues = keyValues + ',' + selected[i].get('getAppraisalId');
}
/*
var conn = new Ext.data.Connection();
conn.request({
url: 'DriveInListingAction',
params: {userAction: 'deleteDriveIn', keys: keyValues, start:0, limit:5 }
});
ds.reload({params:{start:0, limit:5, userAction:'list'}});
*/
ds.reload({params: {userAction: 'deleteDriveIn', keys: keyValues, start:0, limit:5 },mehtod:'post'});
ds.removeAll();
ds.reload({params: {userAction: 'list', keys: keyValues, start:0, limit:5 },mehtod:'get'});
}
else {
grid.getSelectionModel().clearSelections();
}
});
}
});
}

if(Ext.get('assign')) {
Ext.get('assign').on('click', function(){
Ext.MessageBox.alert('Status', 'Not Implemented Yet.');
});
}

if(Ext.get('search')) {
Ext.get('search').on('click', function(){
Ext.MessageBox.alert('Status', 'Not Implemented Yet.');
});
}
}
return {
init : function() {
setupDataSource();
buildGrid();
setupButtons();
},

getDataSource: function() {
return ds;
}
};
}();

Ext.onReady(driveInGrid.init, driveInGrid, true);

function renderPhone(value) {
var phoneNumber;
if (value !== '' ) {
phoneNumber = '(' + value.substring(0,3) + ') ' + value.substring(3, 6) + '-' + value.substring(6);
return (phoneNumber);
}
}







thanks guys :)
i never intended this to be used with large datasets, but it's clear you guys have a real need for it.

reading from the posts here i suggest the following:
- decouple sorting algoritme from the pagingproxy. (so you can use whatever algoritme you want)
- add extra options like; the refresh option, cache sorting between requests, etc

possible extra features:
- implement partial / background loading.
- prefetching pages in memory.

thinks to check:
- make sure the dataset is buffered only onces in memory. (if you have very large in memory datasets you don't want to have X copies lying around)

hendricd
20 May 2008, 7:59 AM
I just posted an important fix for BufferedPagingMemProxy. (http://extjs.com/forum/showthread.php?p=113573#post113573)

It fixes a 'filters running too often' problem. Even quicker now. ;) Doh.

And thanks to @jelt for steering me in the right direction. =D>

snow
21 May 2008, 4:03 AM
Update2 - Issues resolved code working :)

GridPanel needed "autoHeight: true",
working code posted in next post

----------------
Update 1: some progress

seems the Method has changed its name from a previous example, or I had it complete wrong.

Either way, by changing the call to "proxy: new Ext.data.PagingMemoryProxy(myData)" , it now renders
and has a paging bar, :) However no data is displayed :(( , it does count 239 records which is correct.....

--------------------
Hi,

My code does not render, JSLint says output is ok,

Firebug says ' Ext.ux.data.PagingMemoryProxy is not a constructor'

ExtJS version is 2.1 , and I have an include defined before the code

<script type="text/javascript" src="/ext/Ext.ux.data.PagingMemoryProxy.js"></script>

Thanks





Ext.onReady(function() {


Ext.namespace("Ext.ux.data");

Ext.grid.myData = [
['<style type=text/css>.x-grid3-cell-inner, .x-grid3-hd-inner { white-space:normal !important; }</style><a href=/prod/syslog.pl?mode=syslog&act=edit&id=428416&type=ID&stage=1>428416</a>','<style type=text/css>.x-grid3-cell-inner, .x-grid3-hd-inner { white-space:normal !important; }</style><a href=/prod/syslog.pl?mode=syslog&act=edit&id=428416&type=FromHost&stage=1>1.1.1.1</a>','<style type=text/css>.x-grid3-cell-inner, .x-grid3-hd-inner { white-space:normal !important; }</style><a href=/prod/syslog.pl?mode=syslog&act=edit&id=428416&type=DeviceReportedTime&stage=1>2008-05-21 11:52:23</a>','<style type=text/css>.x-grid3-cell-inner, .x-grid3-hd-inner { white-space:normal !important; }</style><a href=/prod/syslog.pl?mode=syslog&act=edit&id=428416&type=Facility&stage=1>DAEMON</a>','<style type=text/css>.x-grid3-cell-inner, .x-grid3-hd-inner { white-space:normal !important; }</style><a href=/prod/syslog.pl?mode=syslog&act=edit&id=428416&type=Priority&stage=1>LOG_INFO</a>','<style type=text/css>.x-grid3-cell-inner, .x-grid3-hd-inner { white-space:normal !important; }</style><a href=/prod/syslog.pl?mode=syslog&act=edit&id=428416&type=Message&stage=1> synchronized to 1.1.1.2, stratum 3</a>','<style type=text/css>.x-grid3-cell-inner, .x-grid3-hd-inner { white-space:normal !important; }</style><a href=/prod/syslog.pl?mode=syslog&act=edit&id=428416&type=SysLogTag&stage=1>ntpd[2867]:</a>','<style type=text/css>.x-grid3-cell-inner, .x-grid3-hd-inner { white-space:normal !important; }</style><a href=/prod/syslog.pl?mode=syslog&act=delete&id=428416>Delete</a>']
,
['<style type=text/css>.x-grid3-cell-inner, .x-grid3-hd-inner { white-space:normal !important; }</style><a href=/prod/syslog.pl?mode=syslog&act=edit&id=428417&type=ID&stage=1>428417</a>','<style type=text/css>.x-grid3-cell-inner, .x-grid3-hd-inner { white-space:normal !important; }</style><a href=/prod/syslog.pl?mode=syslog&act=edit&id=428417&type=FromHost&stage=1>1.1.1.1</a>','<style type=text/css>.x-grid3-cell-inner, .x-grid3-hd-inner { white-space:normal !important; }</style><a href=/prod/syslog.pl?mode=syslog&act=edit&id=428417&type=DeviceReportedTime&stage=1>2008-05-21 12:00:01</a>','<style type=text/css>.x-grid3-cell-inner, .x-grid3-hd-inner { white-space:normal !important; }</style><a href=/prod/syslog.pl?mode=syslog&act=edit&id=428417&type=Facility&stage=1>CRON</a>','<style type=text/css>.x-grid3-cell-inner, .x-grid3-hd-inner { white-space:normal !important; }</style><a href=/prod/syslog.pl?mode=syslog&act=edit&id=428417&type=Priority&stage=1>LOG_INFO</a>','<style type=text/css>.x-grid3-cell-inner, .x-grid3-hd-inner { white-space:normal !important; }</style><a href=/prod/syslog.pl?mode=syslog&act=edit&id=428417&type=Message&stage=1> (root) CMD (/usr/lib/sa/sa1 1 1)</a>','<style type=text/css>.x-grid3-cell-inner, .x-grid3-hd-inner { white-space:normal !important; }</style><a href=/prod/syslog.pl?mode=syslog&act=edit&id=428417&type=SysLogTag&stage=1>crond[24460]:</a>','<style type=text/css>.x-grid3-cell-inner, .x-grid3-hd-inner { white-space:normal !important; }</style><a href=/prod/syslog.pl?mode=syslog&act=delete&id=428417>Delete</a>']
,
['<style type=text/css>.x-grid3-cell-inner, .x-grid3-hd-inner { white-space:normal !important; }</style><a href=/prod/syslog.pl?mode=syslog&act=edit&id=428418&type=ID&stage=1>428418</a>','<style type=text/css>.x-grid3-cell-inner, .x-grid3-hd-inner { white-space:normal !important; }</style><a href=/prod/syslog.pl?mode=syslog&act=edit&id=428418&type=FromHost&stage=1>1.1.1.1</a>','<style type=text/css>.x-grid3-cell-inner, .x-grid3-hd-inner { white-space:normal !important; }</style><a href=/prod/syslog.pl?mode=syslog&act=edit&id=428418&type=DeviceReportedTime&stage=1>2008-05-21 12:01:01</a>','<style type=text/css>.x-grid3-cell-inner, .x-grid3-hd-inner { white-space:normal !important; }</style><a href=/prod/syslog.pl?mode=syslog&act=edit&id=428418&type=Facility&stage=1>CRON</a>','<style type=text/css>.x-grid3-cell-inner, .x-grid3-hd-inner { white-space:normal !important; }</style><a href=/prod/syslog.pl?mode=syslog&act=edit&id=428418&type=Priority&stage=1>LOG_INFO</a>','<style type=text/css>.x-grid3-cell-inner, .x-grid3-hd-inner { white-space:normal !important; }</style><a href=/prod/syslog.pl?mode=syslog&act=edit&id=428418&type=Message&stage=1> (root) CMD (run-parts /etc/cron.hourly)</a>','<style type=text/css>.x-grid3-cell-inner, .x-grid3-hd-inner { white-space:normal !important; }</style><a href=/prod/syslog.pl?mode=syslog&act=edit&id=428418&type=SysLogTag&stage=1>crond[24464]:</a>','<style type=text/css>.x-grid3-cell-inner, .x-grid3-hd-inner { white-space:normal !important; }</style><a href=/prod/syslog.pl?mode=syslog&act=delete&id=428418>Delete</a>']

];

var myReader = new Ext.data.ArrayReader({}, [
{name: 'ID'},
{name: 'Host'},
{name: 'Date_Time'},
{name: 'Facility'},
{name: 'Priority'},
{name: 'Message'},
{name: 'Tag'},
{name: 'Delete'}
]);

var dstore = new Ext.data.Store({
proxy: new Ext.ux.data.PagingMemoryProxy(Ext.grid.myData),
reader: myReader,
autoLoad: {params: {start: 0, limit: 2}}
});



var grid = new Ext.grid.GridPanel({
store: dstore,

cm: new Ext.grid.ColumnModel([
{header: 'ID', width: 20, sortable: true, locked:true, dataIndex: 'ID'},
{header: 'Host', width: 100, sortable: true, locked:true, dataIndex: 'Host'},
{header: 'Date_Time', width: 120, sortable: true, locked:true, dataIndex: 'Date_Time'},
{header: 'Facility', width: 100, sortable: true, locked:true, dataIndex: 'Facility'},
{header: 'Priority', width: 100, sortable: true, locked:true, dataIndex: 'Priority'},
{header: 'Message', width: 200, sortable: true, locked:true, dataIndex: 'Message'},
{header: 'Tag', width: 80, sortable: true, locked:true, dataIndex: 'Tag'},
{header: 'Delete', width: 60, css: '{white-space:normal;}', sortable: false, dataIndex: 'Delete'}
]),
viewConfig: {
forceFit: true,
autoFill : true
},
renderTo: 'dgrid',
title: 'Grid syslog Management',
autoFit: true,
autoExpandColumn: 'Host',
frame: true,
id: 'grid',
bbar: new Ext.PagingToolbar({
pageSize: 2,
store: dstore,
displayInfo: true
})
});

grid.getSelectionModel().selectFirstRow();

});

snow
21 May 2008, 7:10 AM
Clean post of working code for reference, with ExtJS version 2.1




Ext.onReady(function() {


//Ext.namespace("Ext.ux.data");

Ext.grid.myData = [

['<style type=text/css>.x-grid3-cell-inner, .x-grid3-hd-inner { white-space:normal !important; }</style><a href=/prod/syslog.pl?mode=syslog&act=edit&id=433224&type=ID&stage=1>433224</a>','<style type=text/css>.x-grid3-cell-inner, .x-grid3-hd-inner { white-space:normal !important; }</style><a href=/prod/syslog.pl?mode=syslog&act=edit&id=433224&type=FromHost&stage=1>1.1.1.1</a>','<style type=text/css>.x-grid3-cell-inner, .x-grid3-hd-inner { white-space:normal !important; }</style><a href=/prod/syslog.pl?mode=syslog&act=edit&id=433224&type=DeviceReportedTime&stage=1>2008-05-21 15:11:30</a>','<style type=text/css>.x-grid3-cell-inner, .x-grid3-hd-inner { white-space:normal !important; }</style><a href=/prod/syslog.pl?mode=syslog&act=edit&id=433224&type=Facility&stage=1>DAEMON</a>','<style type=text/css>.x-grid3-cell-inner, .x-grid3-hd-inner { white-space:normal !important; }</style><a href=/prod/syslog.pl?mode=syslog&act=edit&id=433224&type=Priority&stage=1>LOG_INFO</a>','<style type=text/css>.x-grid3-cell-inner, .x-grid3-hd-inner { white-space:normal !important; }</style><a href=/prod/syslog.pl?mode=syslog&act=edit&id=433224&type=Message&stage=1> synchronized to 1.1.1.2, stratum 3</a>','<style type=text/css>.x-grid3-cell-inner, .x-grid3-hd-inner { white-space:normal !important; }</style><a href=/prod/syslog.pl?mode=syslog&act=edit&id=433224&type=SysLogTag&stage=1>ntpd[2867]:</a>','<style type=text/css>.x-grid3-cell-inner, .x-grid3-hd-inner { white-space:normal !important; }</style><a href=/prod/syslog.pl?mode=syslog&act=delete&id=433224>Delete</a>']
,
['<style type=text/css>.x-grid3-cell-inner, .x-grid3-hd-inner { white-space:normal !important; }</style><a href=/prod/syslog.pl?mode=syslog&act=edit&id=433225&type=ID&stage=1>433225</a>','<style type=text/css>.x-grid3-cell-inner, .x-grid3-hd-inner { white-space:normal !important; }</style><a href=/prod/syslog.pl?mode=syslog&act=edit&id=433225&type=FromHost&stage=1>1.1.1.1</a>','<style type=text/css>.x-grid3-cell-inner, .x-grid3-hd-inner { white-space:normal !important; }</style><a href=/prod/syslog.pl?mode=syslog&act=edit&id=433225&type=DeviceReportedTime&stage=1>2008-05-21 15:14:45</a>','<style type=text/css>.x-grid3-cell-inner, .x-grid3-hd-inner { white-space:normal !important; }</style><a href=/prod/syslog.pl?mode=syslog&act=edit&id=433225&type=Facility&stage=1>DAEMON</a>','<style type=text/css>.x-grid3-cell-inner, .x-grid3-hd-inner { white-space:normal !important; }</style><a href=/prod/syslog.pl?mode=syslog&act=edit&id=433225&type=Priority&stage=1>LOG_INFO</a>','<style type=text/css>.x-grid3-cell-inner, .x-grid3-hd-inner { white-space:normal !important; }</style><a href=/prod/syslog.pl?mode=syslog&act=edit&id=433225&type=Message&stage=1> synchronized to 11.1.1.2, stratum 3</a>','<style type=text/css>.x-grid3-cell-inner, .x-grid3-hd-inner { white-space:normal !important; }</style><a href=/prod/syslog.pl?mode=syslog&act=edit&id=433225&type=SysLogTag&stage=1>ntpd[2867]:</a>','<style type=text/css>.x-grid3-cell-inner, .x-grid3-hd-inner { white-space:normal !important; }</style><a href=/prod/syslog.pl?mode=syslog&act=delete&id=433225>Delete</a>']
,
['<style type=text/css>.x-grid3-cell-inner, .x-grid3-hd-inner { white-space:normal !important; }</style><a href=/prod/syslog.pl?mode=syslog&act=edit&id=433226&type=ID&stage=1>433226</a>','<style type=text/css>.x-grid3-cell-inner, .x-grid3-hd-inner { white-space:normal !important; }</style><a href=/prod/syslog.pl?mode=syslog&act=edit&id=433226&type=FromHost&stage=1>1.1.1.1</a>','<style type=text/css>.x-grid3-cell-inner, .x-grid3-hd-inner { white-space:normal !important; }</style><a href=/prod/syslog.pl?mode=syslog&act=edit&id=433226&type=DeviceReportedTime&stage=1>2008-05-21 15:16:55</a>','<style type=text/css>.x-grid3-cell-inner, .x-grid3-hd-inner { white-space:normal !important; }</style><a href=/prod/syslog.pl?mode=syslog&act=edit&id=433226&type=Facility&stage=1>DAEMON</a>','<style type=text/css>.x-grid3-cell-inner, .x-grid3-hd-inner { white-space:normal !important; }</style><a href=/prod/syslog.pl?mode=syslog&act=edit&id=433226&type=Priority&stage=1>LOG_INFO</a>','<style type=text/css>.x-grid3-cell-inner, .x-grid3-hd-inner { white-space:normal !important; }</style><a href=/prod/syslog.pl?mode=syslog&act=edit&id=433226&type=Message&stage=1> synchronized to 1.1.1.12, stratum 3</a>','<style type=text/css>.x-grid3-cell-inner, .x-grid3-hd-inner { white-space:normal !important; }</style><a href=/prod/syslog.pl?mode=syslog&act=edit&id=433226&type=SysLogTag&stage=1>ntpd[2867]:</a>','<style type=text/css>.x-grid3-cell-inner, .x-grid3-hd-inner { white-space:normal !important; }</style><a href=/prod/syslog.pl?mode=syslog&act=delete&id=433226>Delete</a>']

];


var myReader = new Ext.data.ArrayReader({}, [
{name: 'ID'},
{name: 'Host'},
{name: 'Date_Time'},
{name: 'Facility'},
{name: 'Priority'},
{name: 'Message'},
{name: 'Tag'},
{name: 'Delete'}
]);

var dstore = new Ext.data.Store({
proxy: new Ext.data.PagingMemoryProxy(Ext.grid.myData),
reader: myReader,
autoLoad: {params: {start: 0, limit: 9}}
});



var grid = new Ext.grid.GridPanel({
store: dstore,

cm: new Ext.grid.ColumnModel([
{header: 'ID', width: 20, sortable: true, locked:true, dataIndex: 'ID'},
{header: 'Host', width: 100, sortable: true, locked:true, dataIndex: 'Host'},
{header: 'Date_Time', width: 120, sortable: true, locked:true, dataIndex: 'Date_Time'},
{header: 'Facility', width: 100, sortable: true, locked:true, dataIndex: 'Facility'},
{header: 'Priority', width: 100, sortable: true, locked:true, dataIndex: 'Priority'},
{header: 'Message', width: 200, sortable: true, locked:true, dataIndex: 'Message'},
{header: 'Tag', width: 80, sortable: true, locked:true, dataIndex: 'Tag'},
{header: 'Delete', width: 60, css: '{white-space:normal;}', sortable: false, dataIndex: 'Delete'}
]),
viewConfig: {
forceFit: true,
autoFill : true
},
title: 'Grid syslog Management',
autoFit: true,
autoExpandColumn: 'Host',
autoHeight: true,
frame: true,
id: 'grid',
renderTo: 'dgrid',
bbar: new Ext.PagingToolbar({
pageSize: 9,
store: dstore,
displayInfo: true
})
});

grid.getSelectionModel().selectFirstRow();


});

hendricd
21 May 2008, 7:21 AM
Check the Firebug net tab or see if this script was actually loaded:

<script type="text/javascript" src="/ext/Ext.ux.data.PagingMemoryProxy.js"></script>

snow
22 May 2008, 1:36 AM
I got it working, as mentioined above

I had renamed the file anyway, but the original problem was the method call for the constructor, I had Ext.ux.data.PagingMemoryProxy(Ext.grid.myData), which should
have been Ext.data.PagingMemoryProxy(Ext.grid.myData)

Thanks

crpatrick
30 May 2008, 7:35 AM
Hi there-

Again, thanks for all of the help with this extension...it is a great addition!

I am having a bit of confusion/trouble integrating this though with a grid search feature from jsakalos...if I use his grid search set to local mode, the search will only occur for the current page of my paged grid (and from doing a store.getCount(), I can see that the store only contains the viewable items of the page). With this proxy though, I am assuming I set his search utility to do a remote search, but I am unclear of how to integrate his search to the filters of the proxy? Would I need to write a new search utility, or can I use something built into the extension to perform a search within the proxy?

Basically, setting the remote search on his utilty executes the below...I just can't figure out how to pass in the args needed to filter the passed data, and search my complete data set.

Thanks again for all of the help.
Chris




else {
// clear start (necessary if we have paging)
if(store.lastOptions && store.lastOptions.params) {
store.lastOptions.params[store.paramNames.start] = 0;
}

// get fields to search array
var fields = [];
this.menu.items.each(function(item) {
if(item.checked) {
fields.push(item.dataIndex);
}
});

// add fields and query to baseParams of store
delete(store.baseParams[this.paramNames.fields]);
delete(store.baseParams[this.paramNames.query]);
if (store.lastOptions && store.lastOptions.params) {
delete(store.lastOptions.params[this.paramNames.fields]);
delete(store.lastOptions.params[this.paramNames.query]);
}
if(fields.length) {
store.baseParams[this.paramNames.fields] = Ext.encode(fields);
store.baseParams[this.paramNames.query] = val;
}

// reload store
store.reload();
}

hendricd
30 May 2008, 8:14 AM
@crpatrick -- You'll need to create a filter function capable of using Saki's filter values. Here's one I use with BPMP. Not sure about Saki's filter criteria but, you'll need to modify it to suite your filtering needs and pass that single function in your params during each load:



this.filterFn = null; //define this for re-use (reload) somewhere, and
//set this.filterFn to null when your filters change

var getSakiFilters = function(filterMenu ){

if(this.filterFn) return {filter: this.filterFn}; //already in place?
this.filterFn = null;
// get fields to search array
var fields = [];
filterMenu.items.each(function(item) {
if(item.checked) {
fields.push(item.dataIndex);
}
});
if(!!fields.length){
this.filterFn = function(record){

var f = fields;
var value,srch,type,compare;

for(var i=0, len=f.length; i<len; i++){

value=record.data[f[i].field];

type = f[i].data.type;
srch = f[i].data.value;
compare = f[i].data.comparison; //must emulate
switch(type){
case 'string':
match = new RegExp(srch,"i").test(value);
break;
case 'boolean':

match = String(srch) == String(value);
break;
case 'date':
var format = f[i].data.format;
srch = new Date(srch).clearTime(true);
value = value.clearTime(true);
if(compare =='gt'){
match = value > srch;
} else if(compare =='lt'){
match = value < srch;
}
else if(compare =='eq'){
match = value.format(format) == srch.format(format);

} else match=false;

break;
case 'numeric':
if(compare =='gt'){
match = value > srch;
} else if(compare =='lt'){
match = value < srch;
}
else if(compare =='eq'){
match = value == srch;

} else match=false;

break;
default:
match=true;
}
if(!match){break;}
}
return match;
});
}
return {filter:this.filterFn};
};
Use it something like this:



grid.load({params:Ext.apply({start:0,limit: 25}, getSakiFilters (this.menu) ) } );



Tweak it !

crpatrick
30 May 2008, 8:17 AM
Thanks for the response and help...I'll have a look and tweak away. I know where his params are located, so let me see if I can integrate this in.

Thanks again!

Chris

crpatrick
30 May 2008, 8:26 AM
One quick question...on the grid.load...do you mean store.load? I do a store.load() to set my start/limit params, and I often do a reload on the store...would I be able to pass the filter function into my load routine as you do in the grid.load()? Also, would this then need to be passed into the reload as well? I currently do not reset the start/limit params on a reload.



...

store.load({
params : {
start : 0,
limit : 15
}

});


Thanks again.
Chris

hendricd
30 May 2008, 8:44 AM
Yes, sorry ;) that should, of course, be store.load.

In your case, where the filters could change at any time, you'd be better off defining a beforeload handler to evaluate the filter status on each load/reload:



store.on('beforeload', function( store, options ){
options.params || (options.params = {});
Ext.apply(options.params, getSakiFilters (this.menu) );
});

crpatrick
30 May 2008, 9:09 AM
perfect...I thought I was missing something on the grid load method. :)

Thanks again, and I will try this out.

crpatrick
30 May 2008, 10:48 AM
Just a stupid question in your example...is your "this" your data store or your proxy?

hendricd
30 May 2008, 11:50 AM
if you mean: this.filterFn, just scope it to anywhere accessible.

crpatrick
30 May 2008, 12:09 PM
Sorry...confused...so this.filterFn does not refer to the scope of your store? I set up a store object, and a grid object which references the store. The store uses the Buffered proxy as well, and in the context of my app, I am just confused to the scope of this. Sorry, bare with my ignorance. :)

hendricd
30 May 2008, 12:15 PM
My this is a reference maintained by a custom class (which has, store, columns, grid, etc).

crpatrick
30 May 2008, 12:16 PM
Ahhh....totally clear now.

Thanks again.

crpatrick
30 May 2008, 1:00 PM
Sorry...please ignore the below...the search component I was using was clearing all store options, including the current page. All fixed, and working like a charm. :) Thanks, as always!


Final question....I swear. :) On a paging grid, I've noticed that since I switch to a search similar to the one you posted, modified for my needs/search extension, that if the user pages through the grid, on a reload, it always refreshes back to the first page. If I disable this search code, the user can page, and the page is maintained on reloads of the store. Have you seen something similar?

hendricd
30 May 2008, 1:24 PM
Have you seen the latest version of BPMP on Post #31? (http://extjs.com/forum/showthread.php?p=113573#post113573)

I made a change which might fix that behavior (or worsen it :) ).

crpatrick
30 May 2008, 1:27 PM
I have seen the latest version...just editted my previous response as well...it was an init issue in the search component. :)

Once this release of our product goes out, I am going to have a look at your updates and integrate...for now all is working ideally, but I saw you had a performance boost, which is always a plus with streaming data. :)

Thanks again.

hendricd
30 May 2008, 1:29 PM
Cool, glad you found it.

There is an important fix in there that prevents the filters from being applied twice in certain scenarios. Consider it.

crpatrick
30 May 2008, 2:06 PM
Definitely will...

OK...I lied before as well. :( I did hit one additional problem. Everything is perfect in Firefox...but in IE, for some reason, the bottom toolbar ceases to function with the new filter. I commented out code, and found the issue to be below. If I remove the filterFn, all is ok in both browsers...but adding it back, paging stops working, search doesn't work, etc...yet there are no jscript errors. Typically, I've seen this when a semi colon is missing, but cannot find anything wrong in this. :(




dataSource.on('beforeload', function(store, options) {
options.params || (options.params = {});
Ext.apply(options.params, getSakiFilters(this));
});

var getSakiFilters = function(obj) {

filterFn = null;

if (typeof obj.baseParams["fields"] == "undefined")
return;
if (typeof obj.baseParams["query"] == "undefined")
return;

// get fields to search array
var fields = [];
var searchFields = Ext.decode(dataSource.baseParams["fields"]);

if (!!searchFields.length) {

filterFn = function(record) {

var f = searchFields;

var value, srch, type, compare;
srch = dataSource.baseParams["query"];

for (var i = 0, len = f.length; i < len; i++) {

value = record.data[f];
value = value instanceof Date
? value.format(this.dateFormat
|| record.fields.get(f[I]).dateFormat)
: value;
match = new RegExp(srch, "gi").test(value);

if (match) {
break;
}
} // End field loop

return match;

} // End filterFn

} // End if search fields

return {
filter : filterFn
};

}; // End function getSakiFilters



To debug, I then tried the below, which still has IE issues...



dataSource.on('beforeload', function(store, options) {
options.params || (options.params = {});
Ext.apply(options.params, getSakiFilters(this));
});

var getSakiFilters = function(obj) {

filterFn = null;

if (typeof obj.baseParams["fields"] == "undefined")
return;
if (typeof obj.baseParams["query"] == "undefined")
return;

// get fields to search array
var fields = [];
var searchFields = Ext.decode(dataSource.baseParams["fields"]);

if (!!searchFields.length) {

filterFn = function(record) {

} // End filterFn

} // End if search fields

return {
filter : filterFn
};

}; // End function getSakiFilters



Then, it finally "re-enables" the toolbar if I remove the filterFn = function(record)...altogether. Not sure what is the issue there though.

hendricd
31 May 2008, 7:23 AM
@crpatrick -- As indicated on post #31, you'll need this Array.proto for IE:



//Adds the requisite Array.prototype filter
Ext.applyIf(Array.prototype, {
filter: function(iter, scope) {
var results = [];
Ext.each(this, function(value, index) {
if (iter.call(scope, value, index)) results.push(value);
});
return results;
});
Add that somewhere and see what happens.

crpatrick
31 May 2008, 8:03 AM
That did it....thanks again. :)

elDub
2 Jun 2008, 6:47 AM
Doug,

I must be missing something really simple here. I'm trying to use the getSakiFilters function but it keeps failing on me. The following code is collecting an array of strings that represent the record fields:


var fields = [];
filterMenu.items.each(function(item) {
if(item.checked) fields.push(item.dataIndex);
});


but in the generated filterFn it is trying to access attributes of the strings as if they were full objects:


this.filterFn = function(record){
var f = fields;
var value,srch,type,compare;
for(var i=0, len=f.length; i<len; i++){
value=record.data[f[i].field];


Am I missing something here? My grid is being redefined by the metadata property that is coming back from the server... is that possibly what is different?

-Lonnie

hendricd
2 Jun 2008, 7:00 AM
@elBuf -- You are correct. I just pasted that from my implementation. ;)

You would need to decide on an approach at field 'identification' that's appropriate for Saki's field references(menuItems) and your record layout/reader.

If you're going to stick with menuItem-based index, this would be more appropriate:


value=record.data[f[i]];That way, it could handle it either as an array refrence: record.data[12],
or, an object member reference : record.data['lastName']

snow
3 Jun 2008, 5:44 AM
Is it possible to use Grid Filter with PagingMemoryProxy and local store , under 2.1 ?

My Grid renders, and has the various filters defined, but there is no
update to the grid once a filter selection is made.

Assuming it can be done .... is it possible to filter on all pages at once rather than just
the one page on screen

Thanks




Ext.onReady(function() {

Ext.menu.RangeMenu.prototype.icons = {
gt: '/ext/img/greater_then.png',
lt: '/ext/img/less_then.png',
eq: '/ext/img/equals.png'
};
Ext.grid.filter.StringFilter.prototype.icon = '/ext/img/find.png';
Ext.state.Manager.setProvider(new Ext.state.CookieProvider());





//Ext.namespace("Ext.ux.data");

Ext.grid.myData = [
['<style type=text/css>.x-grid3-cell-inner, .x-grid3-hd-inner { white-space:normal !important; }</style><a href=/prod/syslog.pl?mode=syslog&act=edit&id=428192&type=ID&stage=1>428192</a>',
'<style type=text/css>.x-grid3-cell-inner, .x-grid3-hd-inner { white-space:normal !important; }</style><a href=/prod/syslog.pl?mode=syslog&act=edit&id=428192&type=FromHost&stage=1>1.1.1.1</a>',
'<style type=text/css>.x-grid3-cell-inner, .x-grid3-hd-inner { white-space:normal !important; }</style><a href=/prod/syslog.pl?mode=syslog&act=edit&id=428192&type=DeviceReportedTime&stage=1>2008-05-20 15:43:44</a>',
'<style type=text/css>.x-grid3-cell-inner, .x-grid3-hd-inner { white-space:normal !important; }</style><a href=/prod/syslog.pl?mode=syslog&act=edit&id=428192&type=Facility&stage=1>KERN</a>',
'<style type=text/css>.x-grid3-cell-inner, .x-grid3-hd-inner { white-space:normal !important; }</style><a href=/prod/syslog.pl?mode=syslog&act=edit&id=428192&type=Priority&stage=1>LOG_INFO</a>',
'<style type=text/css>.x-grid3-cell-inner, .x-grid3-hd-inner { white-space:normal !important; }</style><a href=/prod/syslog.pl?mode=syslog&act=edit&id=428192&type=Message&stage=1>imklog 3.19.1, log source = /proc/kmsg started.</a>',
'<style type=text/css>.x-grid3-cell-inner, .x-grid3-hd-inner { white-space:normal !important; }</style><a href=/prod/syslog.pl?mode=syslog&act=edit&id=428192&type=SysLogTag&stage=1>kernel:</a>',
'<style type=text/css>.x-grid3-cell-inner, .x-grid3-hd-inner { white-space:normal !important; }</style><a href=/prod/syslog.pl?mode=syslog&act=delete&id=428192>Ack</a>']
,
['<style type=text/css>.x-grid3-cell-inner, .x-grid3-hd-inner { white-space:normal !important; }</style><a href=/prod/syslog.pl?mode=syslog&act=edit&id=428193&type=ID&stage=1>428193</a>',
'<style type=text/css>.x-grid3-cell-inner, .x-grid3-hd-inner { white-space:normal !important; }</style><a href=/prod/syslog.pl?mode=syslog&act=edit&id=428193&type=FromHost&stage=1>1.1.1.1</a>',
'<style type=text/css>.x-grid3-cell-inner, .x-grid3-hd-inner { white-space:normal !important; }</style><a href=/prod/syslog.pl?mode=syslog&act=edit&id=428193&type=DeviceReportedTime&stage=1>2008-05-20 15:43:44</a>',
'<style type=text/css>.x-grid3-cell-inner, .x-grid3-hd-inner { white-space:normal !important; }</style><a href=/prod/syslog.pl?mode=syslog&act=edit&id=428193&type=Facility&stage=1>KERN</a>',
'<style type=text/css>.x-grid3-cell-inner, .x-grid3-hd-inner { white-space:normal !important; }</style><a href=/prod/syslog.pl?mode=syslog&act=edit&id=428193&type=Priority&stage=1>LOG_INFO</a>',
'<style type=text/css>.x-grid3-cell-inner, .x-grid3-hd-inner { white-space:normal !important; }</style><a href=/prod/syslog.pl?mode=syslog&act=edit&id=428193&type=Message&stage=1>Inspecting /boot/System.map</a>',
'<style type=text/css>.x-grid3-cell-inner, .x-grid3-hd-inner { white-space:normal !important; }</style><a href=/prod/syslog.pl?mode=syslog&act=edit&id=428193&type=SysLogTag&stage=1>kernel:</a>',
'<style type=text/css>.x-grid3-cell-inner, .x-grid3-hd-inner { white-space:normal !important; }</style><a href=/prod/syslog.pl?mode=syslog&act=delete&id=428193>Ack</a>']

];

var myReader = new Ext.data.ArrayReader({}, [
{name: 'ID'},
{name: 'Host'},
{name: 'Date_Time'},
{name: 'Facility'},
{name: 'Priority'},
{name: 'Message'},
{name: 'Tag'},
{name: 'Ack'}
]);

var filters = new Ext.grid.GridFilters({
filters:[
{type: 'numeric', dataIndex: 'ID'},
{type: 'string', dataIndex: 'Host'},
{type: 'date', dataIndex: 'Date_Time'},
{
type: 'list',
dataIndex: 'Facility',
options: ['KERN','USER','MAIL','DAEMON','AUTH','SYSLOG','LPR','NEWS','UUCP','CRON','AUTHPRIV','FTP','NTP','LOG_AUDIT','LOG_ALERT','CLOCK','LOCAL0','LOCAL1','LOCAL2','LOCAL3','LOCAL4','LOCAL5','LOCAL6','LOCAL7'],
},
{
type: 'list',
dataIndex: 'Priority',
options: ['EMERG','ALERT','CRIT','ERR','WARNING','NOTICE','INFO','DEBUG'],
},
{type: 'string', dataIndex: 'Message'},
{type: 'string', dataIndex: 'Tag'},
{type: 'boolean', dataIndex: 'Ack'}
]});



var dstore = new Ext.data.Store({
proxy: new Ext.data.PagingMemoryProxy(Ext.grid.myData),
reader: myReader,
remoteSort: true,
autoLoad: {params: {start: 0, limit: 9}}
});



var grid = new Ext.grid.GridPanel({
store: dstore,

cm: new Ext.grid.ColumnModel([
{header: 'ID', width: 20, sortable: true, locked:true, dataIndex: 'ID'},
{header: 'Host', width: 100, sortable: true, locked:true, dataIndex: 'Host'},
{header: 'Date_Time', width: 120, sortable: true, locked:true, dataIndex: 'Date_Time'},
{header: 'Facility', width: 100, sortable: true, locked:true, dataIndex: 'Facility'},
{header: 'Priority', width: 100, sortable: true, locked:true, dataIndex: 'Priority'},
{header: 'Message', width: 200, sortable: true, locked:true, dataIndex: 'Message'},
{header: 'Tag', width: 80, sortable: true, locked:true, dataIndex: 'Tag'},
{header: 'Ack', width: 60, css: '{white-space:normal;}', sortable: false, dataIndex: 'Ack'}
]),
viewConfig: {
forceFit: true,
autoFill : true
},
title: 'Grid syslog Management',
autoFit: true,
autoExpandColumn: 'Host',
autoHeight: true,
frame: true,
enableColLock: false,
loadMask: true,
plugins: filters,
id: 'grid',
renderTo: 'dgrid',
bbar: new Ext.PagingToolbar({
pageSize: 9,
store: dstore,
plugins: filters,
displayInfo: true
})
});

grid.getSelectionModel().selectFirstRow();

grid.render();

// trigger the data store load
//dstore.load({params:{start:0, limit:15}});


});

elDub
3 Jun 2008, 11:22 AM
Doug,

Are there any issues with using your plugin under 2.1? I am finding issues when clicking on the columns to sort them. There seems to be a new 'third state' to the click pattern, and the ascending/descending triangle doesn't correctly reflect the display.

-Lonnie

hendricd
3 Jun 2008, 1:23 PM
@elDub -- No I haven't used either PMP on 2.1 yet. Couldn't comment on that.

trbs
4 Jun 2008, 12:24 PM
elDub; i also have not been able to try things out with Extjs 2.1 but from what i've seen so far ext.data and friends have not been changed much. So i expect things to work on 2.1. (again i have not tested it myself and i would welcome input from people that have :) )

elDub
4 Jun 2008, 12:30 PM
Well I can tell you that if I swap out the Ext libraries with Ext 2.0.2 I don't have the column sorting problems. As soon as I put the 2.1 libraries in place, they appear. I'm sorry to not be able to work on finding out WHY at the moment as work directives are pushing me to "use what works" for now, which means using 2.0.2.

-Lonnie

trbs
4 Jun 2008, 12:48 PM
Cool thanks elDub...
Then at least i know that when i have some time, this will need to be addressed.

elDub
5 Jun 2008, 5:00 AM
@trbs -- Just to clarify... I was using the code provided by hendricd in post #31 (Buffered Paging Memory Proxy), and not the original code earlier in the thread. I hate when I'm checking the wrong code... :D

ftftft
30 Jun 2008, 6:15 AM
The plugin works very nice. Thanks, But I have one concern.

Each page down/up, the code is calling
result = reader.readRecords(this.data); If the data set is fairly large, it would be a serious performance issue.

hendricd
30 Jun 2008, 6:32 AM
Not a problem. the data the reader is reading is a subset of the total results that the PMP is maintaining (based on the start/limit parameters of your load request).

Efex
1 Jul 2008, 8:08 AM
Hi,

Im using crpatrick's code on this post: http://extjs.com/forum/showthread.php?p=175780#post175780

The problem is that when I leave all fields checked for saki's filter parameters, it does not work.
It seems to be a problem with one date field I have on my columns.
Here's the part of the code from crpatrick that handles date:



value = value instanceof Date
? value.format(this.dateFormat
|| record.fields.get(f).dateFormat)
: value;

My store's date field has this format:
dateFormat: 'Y-m-d H:i: s'

but also has a renderer to change the presented format like this:
renderer: Ext.util.Format.dateRenderer('d/m/Y')

So, by making value.format('d/m/Y') my problem is fixed but, is there a way to reference the format on the renderer directlly so I don't put it manually like ('d/m/Y') in case I change that in the future?

mabello
3 Jul 2008, 6:33 AM
@hendricd


...the data the reader is reading is a subset of the total results that the PMP is maintaining (based on the start/limit parameters of your load request).

I download the last code of this extension, and I do agree with ftftft that


result = reader.readRecords(this.data);

is a big performance issue.

The (fake) job of reading a subset of the total result is done by this code:


if (params.start!==undefined && params.limit!==undefined) {
result.records = result.records.slice(params.start, params.start+params.limit);
}

so the reader is always elaborating all the data of course.

I have a case in which I had a real performance issue, using the normal XmlReader in combination with PagingMemoryProxy, and I had to modify a little bit PagingMemoryProxy and create MyXmlReader extending XmlReader to fix the problem; it is an optimized version of the reader: basically the readRecords accepts also another 2 parameters, from and to, and use them to elaborate only the data that has to be elaborated.

The same can be done with JsonReader of course.

Code:


/**
* Ext.ux.data.PagingMemoryProxy.js
*
* A proxy for local / in-browser data structures
* supports paging / sorting / filtering / etc
*
* @file Ext.ux.PagingMemoryProxy.js
* @author Ing. Ido Sebastiaan Bas van Oostveen
*
* @changelog:
* @version 1.4
* @date 21-Februari-2008
* - added filter prototype method for array's
* @version 1.3
* @date 30-September-2007
* - added customFilter config option
* @version 1.2
* @date 29-September-2007
* - fixed several sorting bugs
* @version 1.1
* @date 30-August-2007
* @version 1.0
* @date 22-August-2007
*
*/

Ext.namespace("Ext.ux");
Ext.namespace("Ext.ux.data");

/* Fixes for IE/Opera old javascript versions */
if(!Array.prototype.map){
Array.prototype.map = function(fun){
var len = this.length;
if(typeof fun != "function"){
throw new TypeError();
}
var res = new Array(len);
var thisp = arguments[1];
for(var i = 0; i < len; i++){
if(i in this){
res[i] = fun.call(thisp, this[i], i, this);
}
}
return res;
};
}

if (!Array.prototype.filter){
Array.prototype.filter = function(fun /*, thisp*/){
var len = this.length;
if (typeof fun != "function")
throw new TypeError();

var res = new Array();
var thisp = arguments[1];
for (var i = 0; i < len; i++){
if (i in this){
var val = this[i]; // in case fun mutates this
if (fun.call(thisp, val, i, this))
res.push(val);
}
}
return res;
};
}

/* Paging Memory Proxy, allows to use paging grid with in memory dataset */
Ext.ux.data.PagingMemoryProxy = function(data, config) {
Ext.ux.data.PagingMemoryProxy.superclass.constructor.call(this);
this.data = data;
Ext.apply(this, config);
};

Ext.extend(Ext.ux.data.PagingMemoryProxy, Ext.data.MemoryProxy, {

customFilter: null,

load : function(params, reader, callback, scope, arg) {
params = params || {};
var result;

try {
if(params.start!==undefined && params.limit!==undefined && reader["readerOptimized"] === true)
result = reader.readRecords(this.data, params.start, params.start+params.limit);
else
result = reader.readRecords(this.data);
} catch(e) {
this.fireEvent("loadexception", this, arg, null, e);
callback.call(scope, null, arg, false);
return;
}

// filtering
if (this.customFilter!=null) {
result.records = result.records.filter(this.customFilter);
result.totalRecords = result.records.length;
} else if (params.filter!==undefined) {
result.records = result.records.filter(function(el){
if (typeof(el)=="object"){
var att = params.filterCol || 0;
return String(el.data[att]).match(params.filter)?true:false;
} else {
return String(el).match(params.filter)?true:false;
}
});
result.totalRecords = result.records.length;
}

// sorting
if (params.sort!==undefined) {
// use integer as params.sort to specify column, since arrays are not named
// params.sort=0; would also match a array without columns
var dir = String(params.dir).toUpperCase() == "DESC" ? -1 : 1;
var fn = function(r1, r2){
return r1==r2 ? 0 : r1<r2 ? -1 : 1;
};
var st = reader.recordType.getField(params.sort).sortType;
result.records.sort(function(a, b) {
var v = 0;
if (typeof(a)=="object"){
v = fn(st(a.data[params.sort]), st(b.data[params.sort])) * dir;
} else {
v = fn(a, b) * dir;
}
if (v==0) {
v = (a.index < b.index ? -1 : 1);
}
return v;
});
}

// // paging (use undefined cause start can also be 0 (thus false))
if (params.start!==undefined && params.limit!==undefined && reader["readerOptimized"] === false) {
result.records = result.records.slice(params.start, params.start+params.limit);
}

callback.call(scope, result, arg, true);
}
});

/*
Used in conjuction with PaginationMemoryProxy to have the best performance if readerOptimized = true
*/
Ext.data.MyXmlReader = function(meta, recordType){
meta = meta || {};
Ext.data.XmlReader.superclass.constructor.call(this, meta, recordType || meta.fields);
};
Ext.extend(Ext.data.MyXmlReader, Ext.data.XmlReader, {

readerOptimized: true,
/**
* Create a data block containing Ext.data.Records from an XML document.
* @param {Object} doc A parsed XML document.
* @return {Object} records A data block which is used by an {@link Ext.data.Store} as
* a cache of Ext.data.Records.
*/
readRecords : function(doc, from, to){
var len = null;
/**
* After any data loads/reads, the raw XML Document is available for further custom processing.
* @type XMLDocument
*/
this.xmlData = doc;
var root = doc.documentElement || doc;
var q = Ext.DomQuery;
var recordType = this.recordType, fields = recordType.prototype.fields;
var sid = this.meta.id;
var totalRecords = 0, success = true;
if(this.meta.totalRecords){
totalRecords = q.selectNumber(this.meta.totalRecords, root, 0);
}

if(this.meta.success){
var sv = q.selectValue(this.meta.success, root, true);
success = sv !== false && sv !== 'false';
}
var records = [];
var ns = q.select(this.meta.record, root);
if(!from)
from = 0;
if(!to)
to = ns.length;
to = Math.min(to, ns.length);
for(var i = from; i < to; i++) {
var n = ns[i];
var values = {};
var id = sid ? q.selectValue(sid, n) : undefined;
for(var j = 0, jlen = fields.length; j < jlen; j++){
var f = fields.items[j];
var v = q.selectValue(f.mapping || f.name, n, f.defaultValue);
v = f.convert(v, n);
values[f.name] = v;
}
var record = new recordType(values, id);
record.node = n;
records[records.length] = record;
}

return {
success : success,
records : records,
totalRecords : totalRecords || ns.length
};
}
});

EDIT:
I apologize, this is the 1.x Ext forum, I'm talking about the Ext 2.0 version, so I'm not sure it's the same code.
Thanks

Stripeman
23 Jul 2008, 11:40 PM
Any chance of this becoming part of the base code for Ext ? This is sweet!

trbs
29 Jul 2008, 5:05 AM
yeah pagingmemoryproxy is the same code for both ext1 and ext2

trbs
29 Jul 2008, 5:11 AM
@hendricd

I download the last code of this extension, and I do agree with ftftft that


result = reader.readRecords(this.data);

is a big performance issue.

The (fake) job of reading a subset of the total result is done by this code:


if (params.start!==undefined && params.limit!==undefined) {
result.records = result.records.slice(params.start, params.start+params.limit);
}

so the reader is always elaborating all the data of course.


I remember having a reason for this when i first wrote it... but that has been so long ago that i cannot remember what it was :)

Regretfully i am (and have been) very busy with other projects, that i have little time left to contribute to extjs. When i do i'm sure to take all the posts and changes in this thread and update PagingMemoryProxy to fix this and other issue's.

Unless it does become part of core ExtJS in which case i think they will rewrite it anyways as i have not signed the ExtJS Contract thing. (And if any ExtJS devs are reading this thread, i will grant the use of my extension for inclusion in ExtJS given that my code always remains opensource and credit is given where credit is due)

hikeeba!
28 Aug 2008, 7:33 AM
Is there any way to update the data dynamically using this extension?

I need to programatically update some of the records and have it show up inside my SimpleStore/GridPanel.

Thanks,
John

ksolberg
20 Sep 2008, 3:43 AM
Hello,

I want to dynamically assign new values to the store that uses the PagingMemoryProxy. How do I do that in a correct manner so that the proper events are fired and the PagingToolbar reflects the new dataset?

Code:


var pagingData = [ [0], [1], [2] ];

var pagingStore = new Ext.data.Store({
pruneModifiedRecords: true,
proxy: new Ext.ux.data.PagingMemoryProxy(pagingData),
reader: new Ext.data.ArrayReader({}, [
{name: 'Page'}
])
});

var pagingBar = new Ext.PagingToolbar({
pageSize: 1,
store: pagingStore
});

:

// in a click event somewhere

pagingStore.loadData([ [0], [1] ], false);
This last line obviously won't work as intended, but I guess it gives you a basic idea of what I want to accomplish.

Thanks in advance!

Kenneth

skaue
28 Oct 2008, 5:44 AM
Am I going about this the wrong way? I cannot seem to get data in the combobox.

Here's some snippets:


var EstateInfoData = {data:[{"EstateId":"1","Number":"10","Name":"Test"}]};
var EstateInfo = new Ext.data.Store({
proxy: new Ext.ux.data.PagingMemoryProxy(EstateInfoData),
reader: new Ext.data.JsonReader(
{root:"data"},
Ext.data.Record.create([{"name":"EstateId"},{"name":"Number"},{"name":"Name"}])),
remoteSort:true
});


The reason I want to use a JsonReader is because I already have the combodata as json and not as array, but if this extension is not compatible with json then let me know.

Hwang Jin Kwang
28 Oct 2008, 8:18 PM
Hi all,

Here another one of my fine Ext contributions :">

Ext.ux.data.PagingMemoryProxy
A proxy for local / in-browser data structures which supports paging / sorting / filtering / etc.

Wiki
http://extjs.com/learn/Extention:PagingMemoryProxy

Download
PagingMemoryProxy is part of one of the locale examples i wrote for the official Ext distribution, you can find it under the Ext/examples/locale folder. The User eXtension will be further developed here and can be downloaded at the url below.

See http://ido.nl.eu.org/ext-pagingmemoryproxy/ for a demo and download links.

Online Demo
You can find an example of the PagingMemoryProxy in the official Ext distribution: Multiple Languages Example (http://extjs.com/deploy/ext/examples/locale/multi-lang.html)
The PagingMemoryProxy is used in the bottom grid, that pages and sorts the long Month names of the selected language.

Todo / Future Thought

Anybody has a wish list ?? if so please add to the forum threadChangelog

1.3 : (30-09-2007) Added customFilter config option.
1.2 : (29-09-2007) Fixed several sorting bugs, thanks to dogmatic!
1.1 : fixed sorting algoritm
1.0 : initial release as User eXtension

Hi, PagingMemoryProxy is very nice extension,
but i found the problem, that is,
when i load a large data from database into the ordinary data store.
and by using the PagingMemoryProxy, My Grid only shows the paged data,
and PagingMemoryProxy gets the data from ordinary data store.

But the problem is that when i click the "Next Page" Button on Internet Explorer 7,
whole Browser stops few seconds and renders the paged data without loadmask
while FireFox and Crome works fine.

my code and conceptual architecture is right bellow.

http://fimg.hanmail.net/tenth/img/k/f/k/i/14f14/410/4bfb6f-60827.jpg

the second datastore is pagingmemoryproxy

[code]
function drawGrid(dataStore,fieldsName,urlName,colmModel,myPanel)
{
r_colmModel = colmModel;

var dummyJS = createDS(urlName,fieldsName);
pageSize = Math.floor((document.body.clientHeight-(myPanel.getFrameHeight()+myPanel.getInnerHeight()))/23.9);

myGrid = new xg2.GridPanel({
id:'mygrid1',
store: dummyJS,
cm: colmModel,
width:document.body.clientWidth,
height:(document.body.clientHeight-(myPanel.getFrameHeight()+myPanel.getInnerHeight())),
frame:true,
title:'Submit Results',
iconCls:'icon-grid',
stripeRows:true,
renderTo:document.body,
bbar: new Ext.PagingToolbar({
pageSize: pageSize,
store: dummyJS,
displayInfo: true
})
});
myGrid.render();
window.onresize = function GridResize(){
myGrid.setSize(document.body.clientWidth,(document.body.clientHeight-(myPanel.getFrameHeight()+myPanel.getInnerHeight())));
}
dataStore.on('load', function()
{
if(ds!=null)
{
ds.removeAll();
ds = null;
}
ds = new Ext.data.Store({
proxy: new Ext.ux.data.PagingMemoryProxy(dataStore.reader.jsonData), //jsonData

marmayol
7 Nov 2008, 6:37 AM
hi,
I need to do a local paging, that means, I get all my information in a xml and then I want to show paging, and not showing all together. For exemple, if I have 60 rows, just show 15 first time, 15 more next time and so.. I'm using a Ext.data.GroupingSotre and before to want to use pagingmemoryproxy, I used the option url and put there the url from where I get my xml, in that case is from a .ashx, and it works perfect. But when I want to do the local paging with the normal pagingtoolbar it

renoye
11 Dec 2008, 7:59 PM
hi, I am using Ext.ux.data.PagingMemoryProxy. I have about 100 records. Paging and sorting all work fine. However, the filtering is not working. I debug on PagingMemoryProxy.js. It seems params.filter and params.filterCol is always null, even I did input some filter text. Also the numeric filter menu seems have problem. Those >, < = icon do not show.

Did I miss something? Here are my code. Thanks a lot.
var js = new Ext.data.JsonStore({
id: 'server_store',
root: 'results',
totalProperty: 'total',
proxy: new Ext.data.HttpProxy({
url: '/xms/jsf/ajaxobjects.jsf?type=physervers&dn=dn'
}),
fields: [
{name: 'name', type: 'string', mapping: 'name'},
{name: 'dn', type: 'string', mapping: 'dn'},
{name: 'os', type: 'string', mapping: 'os'},
{name: 'driverVersion', type: 'string', mapping: 'driverVersion'},
{name: 'ports', type: 'string', mapping: 'ports'},
{name: 'nVnic', type: 'int', mapping: 'nVnic'},
{name: 'nVhba', type: 'int', mapping: 'nVhba'},
{name: 'sp', mapping: 'sp'},
]
});
var server_CM = new Ext.grid.ColumnModel([
{
header: "Host Name",
dataIndex: 'name',
width: 150,
sortable: true
},{
header: "Host OS",
dataIndex: 'os',
width: 175,
sortable: true
},{
header: "Xsigo Driver Version",
dataIndex: 'driverVersion',
width: 125,
sortable: true
},{
header: "nVNICs",
dataIndex: 'nVnic',
width: 60,
sortable: true
},{
header: "nVHBAs",
dataIndex: 'nVhba',
width: 60,
sortable: true
},{
header: "Server Profile",
dataIndex: 'sp',
width: 200,
renderer: renderServerProfile,
sortable: true
},{
header: "Chassis Ports",
dataIndex: 'ports',
width: 200,
renderer: renderPorts,
sortable: true
}
]);
var server_filters = new Ext.grid.GridFilters({
filters:[
{type: 'numeric', dataIndex: 'nVnic'},
{type: 'numeric', dataIndex: 'nVhba'},
{type: 'string', dataIndex: 'name'},
{type: 'string', dataIndex: 'os'},
{type: 'string', dataIndex: 'driverVersion'},
{type: 'string', dataIndex: 'sp'},
{type: 'string', dataIndex: 'ports'}
]
});
var servers_grid = new Ext.grid.GridPanel({
el:'maskGrid',
width:1000,
height: 400,
title:'Physical Server Summary',
store: js,
cm:server_CM,
trackMouseOver:false,
loadMask: true
});
js.on('load', function() {
var ds = new Ext.data.Store({
proxy: new Ext.ux.data.PagingMemoryProxy(js.reader.jsonData),
reader: js.reader,
remoteSort: true
});
ds.setDefaultSort('name', 'asc');

servers_grid = new Ext.grid.GridPanel({
el:'tableGrid',
width:1000,
height: 400,
title:'Physical Server Summary',
store: ds,
cm:server_CM,
trackMouseOver:false,
plugins: server_filters,
loadMask: true,
bbar: new Ext.PagingToolbar({
pageSize: 10,
emptyMsg: "No Physical Servers to display",
store: ds,
displayInfo: true,
displayMsg: 'Displaying Physical Servers {0} - {1} of {2}',
plugins: server_filters
})
});
servers_grid.render();
ds.load({params:{start:0, limit:10}});
});// js.onload

renoye
12 Dec 2008, 11:17 AM
I need to add local:true to the filter object

Shivar
6 Feb 2009, 6:30 AM
Hello everyone,

Sorry but i don't speak English, this is a translation of google translate :"> , but I need you ...:(

I am new to Extjs :"> , and I have a problem :(( ... I can not load the data in the Paging grid (example in the ufficial download "ext-2.2/example/local/multi-lang.html") ... I do not understand how do you take the data :(( ... I have an array of data that comes from a Java Servlet, but you do not know what I do (:| ... how to load the data in the grid? :-/

Thanks to everyone who has tried to give me a hand!

Bye Bye!

Shivar

Condor
6 Feb 2009, 7:30 AM
It's a lot easier to use my PagingStore extension (http://extjs.com/forum/showthread.php?t=57386) instead of a PagingMemoryProxy.

Shivar
6 Feb 2009, 8:09 AM
Thank you,
but unfortunately I can not even understand how the data should go ... you explain:

I have a java array of the httpRequest, but then I do not know how to take him to read the data ...

example:

I have:

Array = [ 'diego', 23, 1985, 12/01/2009 12:00, 'staus'],
[...]...

when in jsp, how the data in hand? and then call your PaginStore.js?

I put you here under my grid ...

p.s. if it were possible I would like to simpleStore in this application because we come at the same 10-20 people ....

Thank you for everything and sorry, but I can not understand

my grid:



var grid = new Ext.grid.GridPanel({
store: store,
columns: [
{header: "name", width: 120, dataIndex: 'name', sortable: true},
{header: "age", width: 180, dataIndex: 'age', sortable: true},
{header: "date", width: 115, dataIndex: 'date', sortable: true},
......
],
renderTo:'grid',
width:540,
height:200
});
store.load();
});

Condor
7 Feb 2009, 4:57 AM
var mydata = [
['diego', 23, 1985, '12/01/2009 12:00', 'staus']
];
var store = new Ext.ux.data.SimplePagingStore({
fields: ['name', 'age', 'date', ...],
data: mydata // or url: 'mydata.jsp'
});
var grid = new Ext.grid.GridPanel({
store: store,
columns: [
{header: 'name', width: 120, dataIndex: 'name', sortable: true},
{header: 'age', width: 180, dataIndex: 'age', sortable: true},
{header: 'date', width: 115, dataIndex: 'date', sortable: true},
...
],
bbar: new Ext.grid.PagingToolbar({
store: store,
pageSize: 10
}),
renderTo:'grid',
width:540,
height:200
});
store.load({params: {start: 0, limit: 10}});

Shivar
10 Feb 2009, 12:58 AM
Thanks a lot Condor!
without you I would not be able to do anything!

talshadar
9 Mar 2009, 10:16 AM
Hi,

I'm using the paging memory proxy to load records into a grid. I've setup a right-click menu item to change a property of the record (in this case set it's status to cancelled) - I was wondering if there was a way to have the proxy reload itself? I basically want the grid to refresh to reflect the change just done.

Reloading the datastore that uses the proxy doesn't help - it won't catch the changes. I can't find any way to reload the proxy and the only options I see is to do the load call again. In this case it's a little more complex because the data results can result from several different queries - a non-filtered list, 1 quick searched and 1 from an advanced search page. This makes it a little more difficult to try to rebuild the search params that were used - it would be far far simpler to simply tell the paging memory proxy to reload its self using it's existing information.

Any suggestions??

codeminer
14 Apr 2009, 2:54 PM
hello, please help need a way to delete a record and remove all record when using PagingMemory Proxy

I tried using removeAll method of store but it doesn't work

Thanks in advance

websitesbob
10 Jun 2009, 5:26 AM
I tracked down the paging error. It was how I was declaring the value for the records per page:

This is what I had:


thumbsPagingToolbar = new Ext.PagingToolbar(viewThumbsFooter, dsImageThumbs, {
pageSize: "30",
displayInfo: true,
displayMsg: 'Rows {0} - {1} of {2}',
emptyMsg: "No records to display"
});
I removed the quotes around the pageSize:


thumbsPagingToolbar = new Ext.PagingToolbar(viewThumbsFooter, dsImageThumbs, {
pageSize: 30,
displayInfo: true,
displayMsg: 'Rows {0} - {1} of {2}',
emptyMsg: "No records to display"
});
And boom it works!!! So yay! My holiday is starting off great!!

Thank You talshadar (http://extjs.com/forum/member.php?u=12575)! I've been having exactly the same problem! I tried everything i could possibly think of, but with no success. Never thought it could be so trivial (LOL)
Thanx again..

talshadar
10 Jun 2009, 5:35 AM
I'm glad you figured it out. That's one of the things that drives me nuts about extJS - it can be the simplest tiniest thing that you just can't find. I'm spoiled I guess, PHP has the best documentation I've ever found and I keep wishing extJS was the same. I've given up so many times on resolving issues because of the lack, in my opinion, of real complete examples and documentation. Just one of my pet peeves.

agtashby
11 Jun 2009, 9:18 AM
I ran into a problem with using this. My use case is that I have no access to the remote server, and the remote server does not do paging. It just sends me a lump of anywhere from 0 to 100 rows depending. My viewing space is limited as well, so I can't show a potential 100 rows all at once.

Then, the remote server is also slow. But again, I have no control over it and I have to use it. So rather than refresh everything when a change is made, I wanted to send the change to the server and then just update my local copy of the data. A callback on the submit request would tell me if the update was successful, and when I get that it was successful I can update the records.

But then the proxy doesn't store the records. It stores the original data. The records in my case are a Json store, and some of the original properties can be mapped elsewhere.

I made this function, and it works for me, but please tell me if I'm dumb and there was a better way to do this all along, etc. If its useful to your situation, please feel free to use it, just know that it may have sharp edges as I've only been using Javascript for a few weeks.



// Update our copy of the store with new data.
update: function (records, store, idProperty) {
var count = 0;
var result = '';

// Check to see if the idProperty is mapped to something else.
var oID = store.reader.recordType.getField(idProperty).mapping;
if (oID == null || oID == undefined) {
oID = idProperty;
}

// Is this an array of records, or a single record? Recurse through an array.
if (typeof(records) == 'array') {
while (records[count] != undefined) {
this.update(records[count], store, idProperty);
count = count + 1;
}
}

// This is just a single object
if (typeof(records) == 'object') {
while (this.data.results[count] != undefined) {
// Does this record match the ID property we are looking for?
if (this.data.results[count][oID] == records['data'][idProperty]) {
// Start copying over the data, preserve mappings.
for (var property in records['data']) {
// Check for a mapping.
var oProperty = store.reader.recordType.getField(property).mapping;
if (oProperty == null || oProperty == undefined) {
if (this.data.results[count][property] != undefined) {
oProperty = property;
} else {
// There is no mapping, and no correlating property in the original data. Ignore and proceed.
continue;
}
}
this.data.results[count][oProperty] = records['data'][property];
}
return true;
}
count = count + 1;
}
}
return false;
}
It goes inside the PagingMemoryProxy class.

yyogev
14 Jul 2009, 10:51 AM
Hi,

I tried using PagingMemoryProxy 3.0 RC2, and found out it was not called, as it was overriding load(), but doRequest() is now called in proxy.

The code is pretty much the same, with a little update in the exception handling copied from the MemoryProxy code.

HTH,
Yaron Yogev

calabacita
19 Feb 2010, 4:39 AM
Hello,

I'm trying to paginate the results in a search. The result is shown in a GridPanel, and I am using PagingMemoryProxy to paginate in local mode.
The problem is that the same first fetched results appear in all of the pages in the grid, althought the bottom toolbar change.

This is my relevant code:


var busquedaRecord = new Ext.data.Record.create([
{name: 'codIG', type: 'string'},
{name: 'aplicacion', type: 'string'},
{name: 'proceso', type: 'string'},
{name: 'estado', type: 'string'},
{name: 'criticidad', type: 'string'},
{name: 'descripcion', type: 'string'},
{name: 'fecha', type: 'date', format: 'd/m/Y'}
]);


var arrayReaderJson = new Ext.ux.data.JsonArrayReader({
root : 'items',
totalProperty : 'rowNumber'
},busquedaRecord

);

var result = new Ext.data.JsonStore({
proxy: new Ext.ux.data.PagingMemoryProxy(),
reader: arrayReaderJson
});

var columns = [
{header: "C&oacute;digo IG", width: 70, sortable: true, dataIndex: 'codIG'},
{header: "Aplicaci&oacute;n", width: 75, sortable: true, dataIndex: 'aplicacion'},
{header: "Proceso", width: 75, sortable: true, dataIndex: 'proceso'},
{header: "Estado", width: 75, sortable: true, dataIndex: 'estado'},
{header: "Criticidad", width: 70, sortable: true, dataIndex: 'criticidad'},
{id:'descripcion',header: "Descripci&oacute;n", width: 250, sortable: true, dataIndex: 'descripcion'},
{header: "Fecha creaci&oacute;n", width: 85, sortable: true, renderer: Ext.util.Format.dateRenderer('m/d/Y'), dataIndex: 'fecha'}
];

var paging = new Ext.PagingToolbar({
pageSize: 5,
store: result,
displayInfo: true,
displayMsg: 'Mostrando {0} - {1} de {2}',
emptyMsg: "No existen datos"
});

var busquedaGrid = new Ext.grid.GridPanel({
view: new Ext.grid.GridView(),
store : result,
columns: columns,
autoExpandColumn: 'descripcion',
bbar : paging,
height:250,
width:600
});

var frmIzq = new Ext.FormPanel ({

...
buttons :[{
text: 'Buscar',
iconCls : 'silk-magnifier',
handler : function(){
if(frmIzq.getForm().isValid()){
frmIzq.getForm().submit({
url: 'ServletBuscar',
method:'POST',
failure: ...
success: function (form, request) {
result= new Ext.data.Store({
reader : arrayReaderJson,
proxy: new Ext.ux.data.PagingMemoryProxy(Ext.util.JSON.decode(request.response.responseText))
});
busquedaGrid.store = result;

paging.bindStore(busquedaGrid.getStore());
busquedaGrid.footer = paging;

busquedaGrid.render();
result.load({params:{start:0, limit:5}});

busquedaGrid.store.commitChanges();
busquedaGrid.getView().refresh();
}
});

}
}
}
});all of this code is in a class Ext.Panel, that is invoked from ready function, inside on a Ext.Viewport var.