ExtJS Hack: Dynamic ComboBox & Remote On-Demand Loading With Local Filtering
By Angsuman Chakraborty, Gaea News NetworkMonday, August 20, 2007
In ExtJS you can create ComboBox which loads data from the server. You can also code so that new data is loaded from the server in response to an event like changing selection of another ComboBox. However it also means that the filtering is done remotely which is slow.
In ExtJS ComboBox automatic filtering is a nifty capability where the ComboBox items are automatically filtered to show only the values which matches the text you typed so far. It can also auto-fill the rest for you. This powerful capability comes at a price for remote mode. Every time the data is filtered by sending a query to the server which can be slower than local query.
In many use cases the full data is already on the client side, fetched during the initial loading of the ComboBox. Subsequent filtering can be easily done on the client side. Let’s see how we can solve it.
Update: I have also filed a defect in ExtJS forum to hopefully incorporate the functionality in the core with suggested solutions. The defect details has been provided at the end of this post.
The intuitive approach to this problem is to load the ComboBox on an event handler after setting the baseParams of the store with appropriate parameters. This works in remote mode but not in local mode. Now you want to set the ComboBox to local mode because you want to implement local filtering, right?
The solution is far from obvious. In local mode ComboBox clears the filters of the store which in turn replaces the data in the store with the stored, and obviously stale, snapshot. To solve this you must call combo.store.updateSnapshot() after the combo.store.load() call.
Now where can you get this function? Oh yes…
Ext.data.Store.prototype.updateSnapshot = function() {
this.snapshot = this.data;
}
The on demand loading is accomplished by keeping the data in local mode and then loading the store once (use a boolean to check) on beforequery event handler. You have to use updateSnapshot() function after the load as explained above.
Use cases
Let’s first look at the use cases which I am sure many will agree with.1. I want to load a ComboBox on demand. I have very large number of columns in a grid, each of which has a ComboBox to help selecting a value. I don’t want to load all the data upfront as that slows down the initial loading. So I want to load the data when the ComBox drop-down is clicked. I can easily do that in remote mode but the downside is that the filtering functionality asks the server for filtering. The data I fetched is fixed and it is already on the client, so there is no justification for bothering the server.
2. An alternative scenario is when you have a dynamically loaded ComBox. You would still like to do local filtering, when the data has been fully loaded, for better performance. This might be the one you can better associate with.
Defect
My solution was to keep the ComboBox in local mode but load the store on first access. This works perfectly in remote mode for the dynamically loading case. However it doesn’t work when the mode is local. In local mode the doQuery() calls clearFilter() which replaces the new data in the store with old stale snapshot data.What is needed is to replace the snapshot data in this case with the current data in the store after a successful reload.
The real defect is that in this case clearFilter() shouldn’t replace the store with old snapshot when the store has been refreshed by a call to load.
Solution
My solution was to create a method for this in ComboBox:
Code:Ext.data.Store.prototype.updateSnapshot = function() { this.snapshot = this.data }
And then call this method after loading the ComboBox.
The solution works but I am not fully happy as it isn’t elegant. Looking forward to hear a better idea in solving this problem.
Additional Thoughts
I think there should be a way for clearFilter() to recognize when new data has been loaded versus when filtered data has been loaded for the old data. Both cases uses load().
The solution could be a new configuration parameter to load() which clearFilter() looks for and processes, if available.
Tags: Cases, ExtJS, The client
March 7, 2008: 3:36 pm
I would like to see a full source of how you are accomplishing this, unfortunately just the one snippet for me is not enough to get going. A complete sample would definitely help here. |
harryjudy |
October 25, 2007: 10:56 am
Hello,when I call Ext.data.Store.prototype.updateSnapshot after loading the ComboBox ,the hack had solve. |
Abdel