GWT 2.1 CellTable Shows Only Loading Bar - gwt

Following both the example from the GWT Showcase and the example found at GWT, I implemented a CellTable. The CellTable displays the first 15 results but subsequent pages only displays the loading bar. Attempting to return to the first 15 results shows only the loading bar as well. No errors in the JavaScript console or within the GWT developer console are raised.
Any help or insight that anyone can give would be greatly appreciated.
Further, I tried the following and it too suffered from the same thing happening:
List<String> stringsList = new ArrayList<String>();
for( int i = 0; i < 60; i++){
stringsList.add("" + i);
}
CellTable<String> cellTable = new CellTable();
TextColumn<String> nameColumn = new TextColumn<String>(){
#Override
public String getValue(String string){
return string;
}
};
SimplePager.Resources pagerResources = GWT.create(SimplePager.Resources.class);
SimplePager pager = new SimplePager(TextLocation.CENTER, pagerResources, false, 0, true);
pager.setDisplay(cellTable);
cellTable.addColumn(nameColumn, "App Name");
cellTable.setRowCount(stringsList.size(), true);
cellTable.setRowData(0, stringsList);
RootLayoutPanel.get().add(cellTable);
RootLayoutPanel.get().add(pager);

Why don't use a DataProvider and setList to fill the Table? Somewhere I read that this is the recommended approach and setRowData shouldn't be used (because it can cause some weird behaviour)

I think you need a data provider to push data into the cell table. Add the next code and it should work.
ListDataProvider dataProvider = new ListDataProvider();
dataProvider.setList(stringsList );
dataProvider.addDataDisplay(cellTable);

This happens when there's some problem with setVisibleRange or a similar method. I get this a lot when a list backing the data provider doesn't have enough values, or something. I recommend you trace your program to the point at which you're changing the visible range and check all the values that are going into your methods there.

Related

GWT CellTable rebuilding rows unnecessarily

I have found an interesting issue, and I am wondering if I am misusing or overlooking something. I have a large CellTable that is vertically scrollable. I want to show all the rows at once instead of traditional pagination. So at the bottom of my table I have a row that the user can click to load 50 more rows. I have provided the table with a custom table builder (setTableBuilder(new Builder());). When the user clicks "load more" I query the data, add to the ListDataProvider and call table.setVisibleRange(0, dataProvider.getList().size());.
I put a log statement in the
#Override
public void buildRowImpl(Object rowValue, int absRowIndex) {
}
method to see when it was building rows. I notice that it would build 0-dataProvider.getList().size() (all the rows), then it would build oldLength-dataProvider.getList().size() (the new rows). For instance, if I have 100 rows and then load 50 more it would build 0-150, and then rebuild 100-50. What I want is for it to only build the new rows, obviously.
So I start debugging to see why it is rebuilding the whole table each time. What I found was in com.google.gwt.user.cellview.client.HasDataPresenter it would set the "redrawRequired" flag to true at line 1325:
else if (range1 == null && range0 != null && range0.getStart() == pageStart
&& (replaceDiff >= oldRowDataCount || replaceDiff > oldPageSize)) {
// Redraw if the new data completely overlaps the old data.
redrawRequired = true;
}
So my question is why does it think that the new data completely overlaps the old data?
Am I using something incorrectly, is there a better way? This gets to be quite a slow down when it has to redraw thousands of rows that don't need to be redrawn.
Thanks,
Will
I think that, in this situation, the only way a CellTable can react to the call of the setVisibleRange() method is to redraw all rows.
You have just informed a CellTable that now it has to display new range (0-150 rows) instead of last (0-100 rows). There is no information that rows 0-100 remain unchanged and there is no need to redraw them.
The interesting thing is that you found the new rows are updated (rebuild) twice:
For instance, if I have 100 rows and then load 50 more it would build 0-150, and then rebuild 100-50
I've tried to reproduce this behavior in the smallest example:
public class ListDataProviderTest implements EntryPoint {
private static final int ADD_COUNT = 10;
private int nextVal = 0;
public void onModuleLoad() {
final CellTable<Integer> cellTable = new CellTable<Integer>();
cellTable.addColumn(new TextColumn<Integer>() {
#Override
public String getValue(Integer object) {
return object.toString();
}});
final ListDataProvider<Integer> listDataProvider = new ListDataProvider<Integer>();
listDataProvider.addDataDisplay(cellTable);
RootPanel.get().add(cellTable);
RootPanel.get().add(new Button("Add more...", new ClickHandler() {
#Override
public void onClick(ClickEvent event) {
List<Integer> list = listDataProvider.getList();
for(int i = 0; i < ADD_COUNT; i++)
list.add(nextVal++);
cellTable.setVisibleRange(0, list.size());
}
}));
}
}
But I get all the rows updated once.
Can you confirm that this example reproduces the issue or provide one that is more accurate?
AFAIK a CellTable always redraws all cells.
This is how the renderer from the CellTable works. Although it always redraws all cells, it is in most times still faster than using a FlexTable and only updating a few cells.

Inserting GWT widget into a div element

I'm using a GWT library (gwt-openlayers) which allows me to create a map popup containing arbitrary HTML, similar to Google Maps. I need this HTML to contain a GWT Button widget.
I'm creating some HTML elements on-the-fly like this:
Element outerDiv = DOM.createDiv();
outerDiv.getStyle().setOverflow(Overflow.HIDDEN);
outerDiv.getStyle().setWidth(100, Unit.PCT);
outerDiv.appendChild(new HTML(mapPOI.getHtmlDetails()).getElement());
Button popupButton = new Button("View Property");
popupButton.getElement().getStyle().setFloat(com.google.gwt.dom.client.Style.Float.RIGHT);
outerDiv.appendChild(popupButton.getElement());
Then I'm getting the source HTML for these elements by calling
String src = outerDiv.toString();
and inserting this html into my map marker. Now my map marker displays the content ok, including the button. However, the button won't respond to any events! From what I can gather, this is because the buttons onAttach() method is never being called.
Is there a better way to do this?
Thanks,
Jon
~~~~EDIT~~~~
I'm now trying a new way of doing this, which seems to be the accepted method looking at other similar posts.
First I'm creating my div:
String divId = "popup-" + ref;
String innerHTML = "<div id=\"" +divId + "\"></div>";
Then I'm adding this to my map popup and displaying it (which adds it to the DOM). After the popup has been displayed, I'm getting the Element as follows and trying to wrap a HTMLPanel around it:
Element element = Document.get().getElementById(divId);
HTMLPanel popupHTML = HTMLPanel.wrap(element);
My div element is successfully retrieved. However, HTMLPanel.wrap(element); doesn't complete. The reason for this is that wrap(..) calls RootPanel.detachOnWindowClose(Widget widget), which includes the following assertions:
assert !widgetsToDetach.contains(widget) : "detachOnUnload() called twice "
+ "for the same widget";
assert !isElementChildOfWidget(widget.getElement()) : "A widget that has "
+ "an existing parent widget may not be added to the detach list";
I put some breakpoints in and it seems that the 2nd assertion is failing!
Does anybody have any idea why this might be the case? Should failing this assertion really result in a complete failure of the method (no return)?
Your first approach is good, you just need to register onClick event for your button like this:
DOM.sinkEvents(popupButton.getElement(), Event.ONCLICK);
DOM.setEventListener(popupButton.getElement(), new EventListener() {
#Override
public void onBrowserEvent(Event event) {
//implement the logic after click
}
});
I have checked this, it works 100%!
You might try something like
RootPanel.get("idOfYourMapMarker").add(popupButton);
See RootPanel.get()
Unfortunately, RootPanels are AbsolutePanels which aren't so nice for layout but could work if you just have a simple button to add. You could also try RootLayoutPanel which will give you a LayoutPanel (also not so nice when you just want things to flow). You might end up creating a container widget that does the layout for you, and adding that to the RootPanel.
SimplePanel is a DIV. Perhaps that can be used instead?
You added the element, but you have to keep the hierarchy of the actual GWT Widgets too.
I don't see a clean way to do this, but you could use something like jQuery to grab the button by and ID and add a click handler back to it that would call the original click handler.
private static native void registerEvents(String buttonId, MyClass instance)/*-{
var $ = $wnd.$;
//check click
$('#'+buttonId).live('click', function(e) {
e.preventDefault();
instance.#com.package.MyClass::handleButtonClick(Lcom/google/gwt/event/dom/client/ClickEvent;)(null);
});
}-*/;
Call this registerEvents() either in your onAttach or constructor.
I once had a similar problem. You can use the gwt-openlayer's MapWidget as follows:
private MapWidget createMapWidget() {
final MapOptions defaultMapOptions = new MapOptions();
defaultMapOptions.setDisplayProjection(DEFAULT_PROJECTION);
defaultMapOptions.setNumZoomLevels(TOTAL_ZOOM_LEVELS);
MapWidget mapWidget = new MapWidget(MAP_WIDGET_WIDTH, MAP_WIDGET_HEIGHT, defaultMapOptions);
map = mapWidget.getMap();
return mapWidget;
}
And then add it to any panel be it vertical or horizontal.
MapWidget mapWgt = createMapWidget();
VerticalPanel mainPanel = new VerticalPanel();
mainPanel.add(mapWgt);
...
... add whatever you want
...
You can finally add the created Panel(containing the MapWidget and the gwt widget) to the PopupPanel. Also, you should now be able to add handlers to the gwt button.

GWT SimplePager LastButton issue

I am facing problem with lastButton of SimplePager.
I have 3 pages in celltable, Page size=11 (1 empty record + 10 records(with value)), Total record=26.
I used CustomerPager by extending SimplePager.
In 1st attempt 1+10 records display in celltable : Next & Last page button is enabled (First & Prev button disabled) which is correct.
But LastPage button not working... :( Dont know whats the issue... (event not fires)
Strange behavior:
#1 Last page button is working only when I visit to last page(3 page in my case).
#2 Assume I am on 1st page n I moved to 2nd page(Total 3 pages in celltable). that time all buttons are enabled which is correct.
In this case Last button is working but behave like Next Button
My GWT application integrated into one of our product so cant debug it from client side.
May be index value is improper in setPage(int index) method from AbstractPager
Code flow is as follows for Last button
//From SimplePager
lastPage.addClickHandler(new ClickHandler() {
public void onClick(ClickEvent event) {
lastPage();
}
});
#Override
public void lastPage() {
super.lastPage();
}
// From AbstractPager
/**
* Go to the last page.
*/
protected void lastPage() {
setPage(getPageCount() - 1);
}
protected void setPage(int index) {
if (display != null && (!isRangeLimited || !display.isRowCountExact() || hasPage(index))) {
// We don't use the local version of setPageStart because it would
// constrain the index, but the user probably wants to use absolute page
// indexes.
int pageSize = getPageSize();
display.setVisibleRange(pageSize * index, pageSize);
}
}
or may be some conditions false from above code(from setPage())
actual record = 26 and 3 Empty record (1st Empty record/page)
May b problem with dataSize :|
How I can check number of pages based on the data size?
?
How can I solve this problem?
edit: I found out that the default constructor of the pager doesn't give you a "last" button, but a "fast forward 1000 lines" button instead (horrible, right?) .
call the following constructor like so, and see your problem solved:
SimplePager.Resources resources = GWT.create(SimplePager.Resources.class);
SimplePager simplePager = new SimplePager(TextLocation.CENTER, resources , false, 1000, true);
the first "false" flag turns off the "fastforward button" and the last "true" flag turns on the "last" button.
also the last button will work only if the pager knows the total amount of records you have.
you can call the table's setRowCount function to update the total like so:
int totalRecordsSize = 26; //the total amount of records you have
boolean isTotalExact = true; //is it an estimate or an exact match
table.setRowCount(totalRecordsSize , isTotalExact); //sets the table's total and updates the pager (assuming you called pager.setDisplay(table) before)
if you are working with an attached DataProvider, than all it's updateRowCount method instead (same usage).
Without seeing more of your code, this is a hard question to answer as there could be multiple places where things are going wrong.
I would make sure you call setDisplay(...) on your SimplePager so it has the data it needs calculate its ranges.
If you can't run in devmode, I recommend setting up some GWT logging in the browser (write the logs to a popup panel or something, see this discussion for an example).
I think the problem is related with condition in the setPage(). Try putting SOP before if condition or debug the code
Only added cellTable.setRowCount(int size, boolean isExact) in OnRange change method AsyncDataProvider. My problem is solved :)
protected void onRangeChanged(HasData<RecordVO> display) {
//----- Some code --------
cellTable.setRowCount(searchRecordCount, false);
//----- Some code --------
}

Reload data in GXT grid freezes

Based on the GXT showcase example 'Paging BeanModel Grid' I try to reload the grid when I have done a modifiaction to my data source. I defined the loader like that:
final BasePagingLoader<PagingLoadResult<ModelData>> loader =
new BasePagingLoader<PagingLoadResult<ModelData>>(proxy, new BeanModelReader());
loader.setRemoteSort(true);
The data loads correctly.
When I do:
loader.load();
My paging toolbar just freezes and goes disabled, the grid freezes too and displays what appears to be a loading mask.
I tried to add some events to force a double reload without luck:
grid.addListener(Events.Attach, new Listener<GridEvent<ModelData>>() {
public void handleEvent(GridEvent<ModelData> be) {
loader.load();
}
});
I tried to use the reconfigure(store,cm) option as well and same result.
Any help?
Thanks,
Jordi.
The loading bar grays out so you can see it is working, and the grid may also have a loading message. The code that is working is the server, probably preparing the items.
Set logging messages in your server code (RPC servlet probably), at the beginning and at the end of the call, to see how long they take to run. That is likely where the actual 'freeze' is actually happening, based on the info in your question.
There could be a pause in the browser after that time as well, but in that case the loading circle would stop moving.
To me there is a bug on the grid controller:
Code details:
private final BasePagingLoader<PagingLoadResult<ModelData>> loader;
private Grid<ModelData> grid;
[...]
public ListUsersView(RpcProxy<PagingLoadResult<UserTableEntryBean>> proxy) {
// Create loader
loader = new BasePagingLoader<PagingLoadResult<ModelData>>(proxy, new BeanModelReader());
loader.setRemoteSort(true);
// Create store
store = new ListStore<ModelData>(loader);
FlowLayout layout = new FlowLayout();
layout.setMargins(new Margins(3, 0, 0, 0));
this.setLayout(layout);
final PagingToolBar toolBar = new PagingToolBar(50);
toolBar.bind(loader);
List<ColumnConfig> columns = new ArrayList<ColumnConfig>();
columns.add(new ColumnConfig(UserTableEntryBean.Fields.username.name(), "Username", 100));
columns.add(new ColumnConfig(UserTableEntryBean.Fields.email.name(), "E-mail", 200));
ColumnConfig date = new ColumnConfig(UserTableEntryBean.Fields.creationDate.name(), "Creation date", 100);
date.setDateTimeFormat(DateTimeFormat.getFormat("dd/MM/y"));
columns.add(date);
ColumnModel cm = new ColumnModel(columns);
grid = new Grid<ModelData>(store, cm);
grid.setLoadMask(true);
grid.setBorders(true);
grid.setAutoExpandColumn(UserTableEntryBean.Fields.creationDate.name());
[...]
}
public boolean refreshTable() {
return loader.load();
}

make the gwt celltable row selected

I have a cell Table in GWT with columns , there are 3 rows in each column, I want the first row to get selected by default when the application starts
some thing like this
mycelltable.setselectedrow(index);
is it possible ?
Thanks
her is the code
display.getShortListedCVsBasedOnJob().getResumeDescriptionColumn().setFieldUpdater(
new FieldUpdater<CandidateSummary, String>() {
public void update(int index, CandidateSummary object,
String value) {
fetchResume(cvSelected, shortListedFlag);
}
});
This fetchResume() method calls but only when i select cell of this column , I want to call this fetchResume() method as my application starts, i.e i want to make the 1st cell of the column to be selected byDefault.
Selection is handled by a SelectionModel, based on objects (not indices); so you have to select the first object from your data in the SelectionModel used by the CellTable (have a look at the Using a key provider to track objects as they change sample code in the Celltable javadoc for an example (last sample before nested classes summary).
This could work?
setSelected(Element elem, boolean selected)
see GWT Documentation
CellTable Google Web Toolkit
Hmm I dont see what´s the Celltable is there. I would set the initial Value like this:
int INITAL_SET_ROW = 0;
TableRowElement initalSetElement = yourCellTable.getRowElement(INITAL_SET_ROW);
yourCellTable.setSelected(initialSetElement, true);
You can try to implement it in you´re main Method. Haven´t tested it tho, hope it helps.
Simply;
List<RowType> source = new LinkedList<RowType>();
//put some data to this list
//populate the table
table.setRowCount(source.size(), true);
table.setRowData(0, source);
//for example, you can select the first row
RowType firstRow = source.get(0);
selectionModel.setSelected(firstRow, true);