Hi,
well, this one has been giving me a lot of headache. I have a dropdown that shows a list of accounts from a dataSource. The dropdown is used repeatedly throughout the entire application - in some cases as a means of data-entry (i.e. assign this record to account x); in some cases as a filter (i.e. find all records belonging to account x).
Now, in some of these drop-downs, I want to inject extra values; values like "Any" or "Unassigned". I've been experimenting with different techniques to make this happen, and I don't particularly like any of the solutions I've come up with.
The best solution I found was to not back the dropdown directly with a datasource; but instead query the dataSource directly, get it to return all the results in a callback, store the results in a hashMap, add any extra entries I need and then use the hashMap as a value map for the dropdown. I.e.; like so:
This works fine; but has performance problems - the dataSource of course has to return all results and I have the impression that the SmartGWT marshalling/unmarshalling code for translating java objects into dataSource responses doesn't handle large resultsets very well. From testing, I can tell my dataSource runs the actual query in 120 miliseconds; but somewhere between when I do dsResponse.setData(results) and when the callback happens, 4.5 seconds are lost. It's a very noticeable and very irritating delay in loading the interface; especially when the account dropdown has to be reloaded or when there's more than one dropdown that needs this type of logic on a page.
The other solution is a bit of a hack - it works from a functional and performance point of view, but I don't like the code behind the solution - it's messy.
This solution consists of binding the comboBoxItem directly to the dataSource; and having it ask the dataSource for extra "fake" items by passing data through the criteria. Like so:
The code for the dataSource then retrieves the extraOptionValues and extraOptions arrays, creates "fake" accounts populated with those values before returning them as part of the query. Because dropdowns and selectItems ask for dataSource results in slices, you also need to recalculate the total resultset size and what to actually query for. For instance, let's say I have 3000 accounts and I want two extra options. I now have to tell SmartGWT that there's actually 3002 accounts, insert the fake ones, then recalculate what to query for (SmartGWT asks for 0-75, so I need to give it 0-73), etc.
I have the code for this, it works and it's peformant (since I'm not returning entire resultsets) but it's messy and a LOT of extra work for something so basic.
Is there a third way that I'm missing? Both of these seem awfully complicated for a pretty basic requirement...
well, this one has been giving me a lot of headache. I have a dropdown that shows a list of accounts from a dataSource. The dropdown is used repeatedly throughout the entire application - in some cases as a means of data-entry (i.e. assign this record to account x); in some cases as a filter (i.e. find all records belonging to account x).
Now, in some of these drop-downs, I want to inject extra values; values like "Any" or "Unassigned". I've been experimenting with different techniques to make this happen, and I don't particularly like any of the solutions I've come up with.
The best solution I found was to not back the dropdown directly with a datasource; but instead query the dataSource directly, get it to return all the results in a callback, store the results in a hashMap, add any extra entries I need and then use the hashMap as a value map for the dropdown. I.e.; like so:
Code:
DataSource accountDS = DataSource.get("account"); ComboBoxItem account = new ComboBoxItem("account"); account.setTitle("Account"); public void populateAccounts() { accountDS.fetchData(new Criteria(), new AccountCallback()); } private class AccountCallback implements DSCallback { @Override public void execute(DSResponse response, Object rawData, DSRequest request) { LinkedHashMap<Serializable,String> valueMap = new LinkedHashMap<Serializable,String>(); valueMap.put("Any", "Any"); Record[] results = response.getData(); Log.debug("Found " + results.length + " accounts."); for(Record result : results) { valueMap.put(result.getAttributeAsInt("accountId", result.getAttribute("accountName")); } account.setValueMap(valueMap); } }
The other solution is a bit of a hack - it works from a functional and performance point of view, but I don't like the code behind the solution - it's messy.
This solution consists of binding the comboBoxItem directly to the dataSource; and having it ask the dataSource for extra "fake" items by passing data through the criteria. Like so:
Code:
DataSource accountDS = DataSource.get("account"); ComboBoxItem account = new ComboBoxItem("account"){ @Override protected Criteria getPickListCriteria() { Criteria criteria = new Criteria(); criteria.add("extraOptionValues", new Integer[]{-1,-2}); criteria.add("extraOptions", new String[]{"Any","Unassigned"}; return criteria; } }; account.setTitle("Account"); account.setValueField("accountId"); account.setDisplayField("accountName");
I have the code for this, it works and it's peformant (since I'm not returning entire resultsets) but it's messy and a LOT of extra work for something so basic.
Is there a third way that I'm missing? Both of these seem awfully complicated for a pretty basic requirement...
Comment