I’m thrilled to announce a Sneak Preview of my LiveGrid component based on ExtJS 2.0 RC 1. After I was pretty sure that There is no spill! and I have been Fighting the spill, I refactored my algorithms to work with the ExtJS library.
When I’m speaking of the term “LiveGrid”, I simply refer to a (grid) view representing a large server side backed database. Instead of paging, the view buffers a specific number of records from the database. When scrolling, the position of the “cursor” changes and a request for new data will be send to the server, delivering an updated buffer with the data the new cursor position indicates.
For making this “view” possible, I have overwritten a few classes from the ExtJS-source:
BufferedJsonReader derives from Ext.data.JsonReader and allows to pass a version value representing the current state of the underlying data repository.
The version property is handled server side and should change whenever a record gets added or deleted in the data repository. The store will then be notified and fires the versionchange event if the current version differs from the version-value from a previous request.
BufferedStore derives from Ext.data.Store and introduces a new config option called bufferSize. The bufferSize property represents the maximum number of data which will be available in the store. Let’s say, your database table you’re reading from has a total number of 5000 records, and bufferSize equals to 300, then the store will have 300 records from this table available for reading. The larger your table, the larger this property should be. The value of bufferSize will be sent to the server as the limit parameter.
Here is where the magic happens: BufferedGridView, deriving from Ext.grid.GridView. It is responsible for requesting buffer data and calculating the range of records to fetch from the underlying data repository upon scrolling. It introduces several new events such as beforebuffer, buffer and cursormove. You will also have to pass a config parameter called nearLimit upon creating an instance of BufferedGridView: The value will help the view in calculating a predictive buffer offset: While scrolling down, the view has to decide which records the user wants to read next. If they are not within the current range of buffered data, the view will notify the store to request new data from the server. The start parameter send with the request will determine the position of the data the user requested.
A toolbar you can add to the GridPanel you are using. Similiar to the Ext.PagingToolbar, this component will keep you up to date about the loading state and the current position of your cursor you are moving through the data. It also gives you a reload button to refresh the view with the newest data.
One of the toughest nut to crack was the decision on how to make selections possible in the scope of possible available data and not current available data. The usual row selection model will allways have records available for storing them in the selections set. What if this records are not available, but where requested to mark as selected by the user?
The extended implementation stores selections based upon their assumed position in the data model. Let’s say you have a table with a number of 5000 records, and you allow to select multiple rows at once in the view (using shift & ctrl key). One of the many possible scenarios is teh following: The user loads the view, clicks the first row while holding down shift, then scrolls down and adds the very last row to the selection. What happens here ist that the store will not request every single record that may come into the view while scrolling, so most likely there may have been only two request for data been made: The initial load and a second one to update the buffer when the user reaches the very end of the table. With a bufferSize set to 300, that would be 4400 records which where not loaded, but requested to add to the selection. Those selections will be stored in a property called pendingSelections, represented by their positions in the data model. Using the method getPendingSelections the selection model computes the ranges of records that where marked as selected, but not available in the store during this operation. It’s up to the user to work with this indexes – he can set up a ajax request to fetch this data from the table. But how does the user know this selection is still valid? It may become invalid when rows have been added or deleted in the table, leading to data disintegrity when the user requests those pending selections and deletes the records associated with them. Well, he doesn’t. But the version property and the versionchange event (as mentioned in the BufferedStore introduction) can help him in deciding if he wants to keep the selections or if he wants to clear the selections-set before any operation with this data will be made. Additionally, the BufferedRowSelectionModel introduces a new event selectiondirty that gets fired whenever the selection model can predict that the selected ranges may have become invalid.
That ‘s it for now. I’m giving you an example of a Grid using the above components. I’m still working on it, so the first downloadable release is scheduled for the next week. I will also have a documentation until then.
Enjoy, and leave your comments, suggestions and bug reports here or in the forum thread over at the ExtJS forums.