I have a database with 10,000 items, to which you can add and remove while the app is running.
I have a ListBox that displays at most 100 items, and supports paging.
You can filter and sort on the 10,000 items, which needs to be immediately reflected in the listbox.
I have a button that randomly selects an item as long as it passes the filters.
What is the best set of collections/views to use for this kind of operation?
So far, my first step will be to create an ObservableCollection of ALL items in the database which we will call MainOC.
Then create a List of all items that match the filter by parsing MainOC which we will call FilteredList.
Then create a ListCollectionView based on the above List that holds the first 100 items.
CONS:
You have to recreate the ListCollectionView every time a sort operation is applied.
You have to recreate the ListCollectionView every time you page.
You have to recreate the ListCollectionView every time a filter is changed.
You have to recreate the ListCollectionView every time an item is added or removed to MainOC.
Is there a better approach that I am missing?
For example, I see that you can apply filters to a ListCollectionView. Should I populate my ListCollectionView with all 10,000 items? But then how can I limit how many items my ListBox is displaying?
Should I be doing my filtering and sorting directly against the database? I could build FilteredList directly off the database and create my ListCollectionView based off that, but this still has all the cons listed above.
Looking for any input you can provide!
This is a problem which is easily solved using DynamicData . Dynamic data is based on rx so if you are not familiar with the wonderful Rx I suggest you start learning it. There is quite a bit of a learning curve but but the rewards are huge.
Anyway back to my answer, the starting point of dynamic data is to get some data into a cache which is constructed with a key as follows
var myCache = new SourceCache<MyObject, MyId>(myobject=>myobject.Id)
Obviously being a cache there are methods to add, update and remove so I will not show those here.
Dynamic data provides a load of extensions and some controllers to dynamically interrogate the data. For paging we need a few elements to solve this problem
//this is an extension of observable collection optimised for dynamic data
var collection = new ObservableCollectionExtended<MyObject>();
//these controllers enable dynamically changing filter, sort and page
var pageController = new PageController();
var filterController = new FilterController<T>();
var sortController = new SortController<T>();
Create a stream of data using these controllers and bind the result to the collection like this.
var mySubscription = myCache.Connect()
.Filter(filterController)
.Sort(sortController)
.Page(pageController)
.ObserveOnDispatcher() //ensure we are on the UI thread
.Bind(collection)
.Subscribe() //nothing happens until we subscribe.
At any time you can change the parameters of the controllers to filter, sort, page and bind the data like follows
//to change page
pageController.Change(new PageRequest(1,100));
//to change filter
filterController.Change(myobject=> //return a predicate);
//to change sort
sortController .Change( //return an IComparable<>);
And as if by magic the observable collection will self-maintain when any of the controller parameters change or when any of the data changes.
The only thing you now have to consider is the code you need for loading the database data into the cache.
In the near future I will create a working example of this functionality.
For more info on dynamic data see
Dynamic data on Github
Wpf demo app
Let's assume I have a store:
Buyer,Good,ItemCount,ItemPrice
{'Alice','Apple',5,$.25}
{'Bob','Pear',2,$.35}
{'Bob','Banana',5,$.25}
{'Bob','Pear',4,$.35}
{'Eve','Grapefruit',2,$.40}
And I have a grid in which to display this store's content, and at least a dozen functions scattered all over the place that change this store, changing filters, reloading data from the server, etc.
Is there a fast way to add another grid, which shows every good in a row and every buyer in a column, and how many items of that kind everyone bought in total? This grid should update whenever the original grid is updated.
The way I know, this would require another store, and then I would have to attach to the originalStore's datachanged and filterchanged event and populate the new store by hand every time? Or is there some other solution?
EDIT: I am now looking at pivot grid, as suggested by the first answer, and I have to expand my example a bit, as I stumbled upon a problem I didn't see before:
Buyer,Good,ItemCount,ItemPrice
{'Alice','Apple',5,$.25}
{'Bob','Pear',2,$.35}
{'Bob','Banana',5,$.25}
{'Bob','Pear',4,$.35}
{'Eve','Grapefruit',2,$.40}
{{'Alice','Bob'},'Candlelight Dinner Set',1,$45}
{'Eve',{'Ski mask','Baseball bat'},1,$65}
{'Francis',{'Ski mask','Ski poles'},1,$80}
Where I would want the dinner to show up at both Alice and Bob, and the products sold in a bundle to show up separately.
Try to use PivotGrid for your purpose:
var pivot = new Ext.grid.PivotGrid({
store: yourStore,
aggregator: 'sum',
measure: 'ItemCount',
leftAxis: [
{
dataIndex: 'Buyer'
}
],
topAxis: [
{
dataIndex: 'Good'
}
]
});
Official Pivot Grid Links:
Documentation (Sencha Docs 5.1)
Announcement (Sencha Blog)
Download (Free 30-Day Evaluation)
The Extjs Itemselector component has methods like getValue, getSubmitData, getSubmitValue which will return the keys of the records that are selected.
I am looking for a better way than taking the keys of the records selected from the component and fetching for the record from the store by searching the store in a sequential fashion. This is a very time expensive solution which is not working well for me since the itemselector has a large number of records.
Question : is there a way to retrieve the displayed string/value (in the selected part of the itemselector) along with the keys directly from the component and not as above ?
thanks
Nohsib
This works in my code to get an array of all the records which you can then get the values from, it may not work in yours if you have a different version of Extjs:
itemSelectorField.toField.store.getRange();
Oh and if you want the display values as a string list:
itemSelectorField.toField.store.getRange().collect("display_value_propery_name").join(",");
I am looking at a different way of doing my application.
Actually It's kind of static. My Projects have Categories. Each Category has Subcategories. Categories are containers and Subcategories are element which have values that can be edited.
After analysis of the data , we saw that it was not enough general for it. We are now looking at a Tree Structure. Doing so, we would have Projects filled with Folders/Categories) and those Folders would be filled with other Category/Folders or with SubCategories/Items/Files. That way we can go has deep has we want in complexity.
That is doable, I know it. What I need to know is how hard it will be to implement it in the app.views...
Is it possible to have a single Ext.DataView.dataview display different Ext.DataView.component.DataItem side by side.
Exemple : Having a row in my List that shows a slider and update itself according to it, but that on the 2nd row it is an arrow that on click would open the next level of my Tree.
Visual:
DataView_List
Small Car---------------------------Label------------------------SLIDER
Fuel----------------------------------Label------------------------------ >
SUV----------------------------------Label------------------------TxtField
Small Car and SUV are leaves with different template and Fuel is a category/folder that need to open on click.
So I already have 3 differents templates that would need to show in the same dataview list.
How should I proceed to achieve such results? Is Dataview List the way to good or should I implement my own kind of list inside a container?
If you want to present different kinds of data inside one list or dataview - you can achieve by following strategy:
You still need to use one store to keep it all
In the model class include something like 'record_type' field indicating what kind of data you have
Combine all data you need into one model
Create a template that based on the 'record_type' would render different content
Here is how your template would look like:
<tpl switch="record_type">
<tpl case="car">
<div>CAR + SLIDER</div>
<tpl case="fuel">
<div>FUEL + LABEL</div>
<tpl default">
</tpl>
This is screenshot from my list which contains multiple record types and uses this approach:
I am moderately new to SmartGWT and am trying to figure out how to have a RecordList where each record has the ability to have a SwitchItem attached to it. So basically create a list of selectable items, but those items also will have a SwitchItem on them to enable/disable some behavior.
Any thoughts on how I can accomplish this?
Looking at Record and RecordList it appears that Record extends HashMap and does nothing fancy like what I am wanting...but i wondered if it was possible to set the "description" property with perhaps some html string that creates the SwitchItem...is this way off? And if so...how is the best way to do this?
Use setShowRecordComponents() and createRecordComponent(). Documentation for how these work can be found in the core SmartGWT docs:
http://www.smartclient.com/smartgwt/javadoc/com/smartgwt/client/widgets/grid/ListGrid.html#setShowRecordComponents%28java.lang.Boolean%29
There's no support for "recycle" mode yet. A sample is being created.