I'm using GWT 2.1's CellBrowser with a custom TreeViewModel
. The TreeViewModel in turn uses an AsyncDataProvider
to fetch data dynamically. This all works beautifully- when the user clicks on a node my AsyncDataProvider fetches the results via RPC, and the CellBrowser dutifully displays them.
I feel silly for not being able to figure this out, but how can I programmatically tell the CellBrowser to reload (and display) the data? I'm guessing that I need to somehow get a handle to the AsyncDataProvider for my root node and then call updateRowData() & updateRowCount() on it, but I don't see an obvious way to query the browser (or its model) for the root DataProvider.
I guess I could add code to my AsyncDataProvider constructor that looks for a null argument, and by that means recognize "hey, I'm the root" and store a reference somewhere, but that seems hackish. Surely there's a better way to do this.
Apologies for dumping so much code here, but I don't know how to boil this down to anything simpler and still provide enough context.
My AsyncDataProvider:
private static class CategoryDataProvider extends AsyncDataProvider<Category>
{
private Category selectedCategory;
private CategoryDataProvider(Category selectedCategory)
{
this.selectedCategory = selectedCategory;
}
@Override
protected void onRangeChanged(HasData<Category> display)
{
new AsyncCall<List<Category>>()
{
@Override
protected void callService(AsyncCallback<List<Category>> cb)
{
// default to root
String categoryId = "-1";
if (selectedCategory != null)
{
categoryId = selectedCategory.getCategoryId();
}
// when a category is clicked, fetch its child categories
service.getCategoriesForParent(categoryId, cb);
}
@Override
public void onSuccess(List<Category> result)
{
// update the display
updateRowCount(result.size(), true);
updateRowData(0, result);
}
}.go();
}
}
My model:
private static class CategoryTreeModel implements TreeViewModel
{
private SingleSelectionModel<Category> selectionModel;
public CategoryTreeModel(SingleSelectionModel<Category> selectionModel)
{
this.selectionModel = selectionModel;
}
/**
* @return the NodeInfo that provides the children of the specified category
*/
public <T> NodeInfo<?> getNodeInfo(T value)
{
CategoryDataProvider dataProvider = new CategoryDataProvider((Category) value);
// Return a node info that pairs the data with a cell.
return new TreeViewModel.DefaultNodeInfo<Category>(dataProvider, new CategoryCell(), selectionModel, null);
}
/**
* @return true if the specified category represents a leaf node
*/
public boolean isLeaf(Object value)
{
return value != null && ((Category) value).isLeafCategory();
}
}
And finally, here's how I'm using them:
CategoryTreeModel model = new CategoryTreeModel(selectionModel);
CellBrowser cellBrowser = new CellBrowser(model, null);
It looks like a lot of people are having this same issue. Here's how I handled refreshing the data from an AsyncDataProvider.
First, create an interface that adds the ability to refresh data provider by wrapping the AsyncDataProvider's protected onRangeChanged method. For example...
HasRefresh.java
public interface HasRefresh<HasData<T>>{
/**
* Called when a display wants to refresh
*
* @param display the display to refresh
*/
void refresh(HasData<T> display);
}
Then the CellTable needing to be refreshed can then call into it through an Activity or however your controller logic is setup.
/**
* A custom {@link AsyncDataProvider}.
*/
public class MyAsyncDataProvider extends
AsyncDataProvider<Entity> implements HasRefresh<Entity> {
public void refresh(Entity display){
onRangeChanged(display);
}
/**
* {@link #onRangeChanged(HasData)} is called when the table requests a
* new range of data. You can push data back to the displays using
* {@link #updateRowData(int, List)}.
*/
@Override
protected void onRangeChanged(
HasData<Entity> display) {
currentRange = display.getVisibleRange();
final int start = currentRange.getStart();
dataServiceQuery = context.getEntities();
dataServiceQuery
.execute(new DataServiceQueryHandler<Entity>() {
@Override
public void onQueryResponse(
DataServiceQueryResponse<Entity> response) {
updateRowCount(response.getCount(), true);
updateRowData(start, response.getEntities());
}
});
}// end onRangeChanged()
}// end MyAsyncDataProvider class