GWT SimplePager LastButton issue - gwt

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 --------
}

Related

Wicket 6 - Feedback message not showing until request after the request in which it happened

I have an AjaxButton. The event fires, and I'm testing a scenario where I need to add a feedback and return without committing the change. I add the feedback at the page level (our feedback only shows page level messages...others are showing on component level feedback panels). I add the WebMarkupContainer that contains the feedback panel to the target. This exact thing works on every other button on the page.
But for this button, which happens to be the only one where defaultformprocessing is not false, the feedback doesn't show. To the user's view, nothing happens except our processing veil appears and then disappears. If I hit submit again, THEN the message and feedback are shown. I stuck a timestamp on it to see if it was showing the one from the 2nd request or the 1st. It's from the 1st.
What's more, a breakpoint in the feedback's filter shows that the filter was never called in the 1st request, but is called BEFORE the event processing on the 2nd request. It accepts the message as intended.
I set defaultformprocessing to FALSE on this button as a test, and in fact, messages suddenly work. But of course, that also means the form doesn't get processed. Can someone help me square this circle?
AjaxButton:
add(new AjaxButton("btnCreateRequest", getForm()) {
#Override
public void onSubmit(AjaxRequestTarget target, Form<?> form) {
//stuff happens
target.add(getFeedbackPanelForAjax());
String date = new Date().toGMTString();
System.out.println("ADDING MESSAGE - " + date);
getPage().error("This is a message! " + date);
return;
}
#Override
public void onError(AjaxRequestTarget target, Form<?> form) {
getPage().error("There was an error processing your request");
target.add(getFeedbackPanelForAjax());
target.add(form);
}
}.setVisible(enabled));
UPDATE:
getFeedbackPanelForAjax returns the web markup container that the feedback resides in. I've also tried adding the feedback directly to the target.
public Component getFeedbackPanelForAjax() {
return (Component) getForm().get("feedbackWmc");
}
Where the feedback is added:
feedback = new FRFeedbackPanel("feedback") {
#Override
public boolean isVisible() {
if(anyMessage()){
return true;
} else {
return false;
}
}
};
// feedback container
WebMarkupContainer feedbackWmc = new WebMarkupContainer("feedbackWmc");
getForm().add(feedbackWmc.setOutputMarkupId(true).setOutputMarkupPlaceholderTag(true));
feedbackWmc.add(feedback.setOutputMarkupId(true).setOutputMarkupPlaceholderTag(true));
I can say that through debugging, I put a breakpoint in anyMessage() and it returns false in this case at the same time that getPage().getFeedbackMessages() returns the message correctly. I commented out this override of isVisible() and indeed, the message shows. The problem is, that it means the artifacts of the feedback panel show when there are no messages as well, which is not what we want.
This anyMessage() solution works perfectly when I'm in an event that is defaultformprocessing=false. I suppose I could do an anyMessage() || getPage().getFeedbackMessages(), but my understanding was that anyMessage was supposed to find if there was ANY message in the hierarchy for this panel. Is that not so?
I assume you cannot replicate the problem in a small quickstart?
One idea: I've seen similar problems when the FeedbackPanel collects its messages too early, i.e. before you add the error to the page.
FeedbackMessagesModel keeps the messages to render until the end of the request - maybe some of your code triggers this by accessing the messages model.

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.

Fetch data from server on scrolling in celltable gwt

I need to implement a feature in GWT which is already existing in smartgwt. In smartgwt, we can set a maximum limit of records in a grid is 75. When the record count reaches 75 while scrolling, it again requests the server and fetches another 75 records. Similar functionality I have to implement in GWT. ie, while scrolling, i have to fetch records from server for every 75 records. Is it possible?? Please assist.
You can use the ScrollPanel for check when the user reache the end of the scoll.
You can try this example of code, and adapt it to your case :
String loremIpsum = "a long text..."; // add a long text here for test
ScrollPanel sPanelTest = new ScrollPanel(loremIpsum);
sPanelTest.addScrollHandler(new ScrollHandler() {
#Override
public void onScroll(ScrollEvent event) {
int maxPosition = sPanelTest.getMaximumVerticalScrollPosition();
int currentPosition = sPanelTest.getVerticalScrollPosition();
if(currentPosition == maxPosition)
Window.alert("Tadam !"); // end of the scroll
}
});
Doc of ScrollPanel.
Another example of use.

Why are GWT SimplePager next/last buttons disabled only if range is limited or if the row count isn't exact?

Using GWT 2.5.1, SimplePager.java has this method:
#Override
protected void onRangeOrRowCountChanged() {
HasRows display = getDisplay();
label.setText(createText());
// Update the prev and first buttons.
setPrevPageButtonsDisabled(!hasPreviousPage());
// Update the next and last buttons.
if (isRangeLimited() || !display.isRowCountExact()) {
setNextPageButtonsDisabled(!hasNextPage());
setFastForwardDisabled(!hasNextPages(getFastForwardPages()));
}
}
Why are the next/last buttons enabled/disabled only if range is limited or if the row count isn't exact? I have a pager set to range limited false, and my async data provider specifies that the row count is exact when I update the row count. With this setup, the next/last paging buttons will NEVER be updated!
Am I just using this wrong, or is it a bug?
I worked around the issue by subclassing SimplePager to allow me into that block at the bottom of onRangeOrRowCountChanged():
#Override
protected void onRangeOrRowCountChanged() {
boolean rangeLimited = isRangeLimited();
super.setRangeLimited(true);
super.onRangeOrRowCountChanged();
super.setRangeLimited(rangeLimited);
}
AIUI, if the range is not limited, you explicitly allow the pager to go beyond the available data and show empty pages.
If the row count is not exact, the next button should be enabled, because hasNextPage will return true (the fast-forward will be disabled though if it goes beyond the known –though inexact– number of rows). This applies whether the range is limited or not, which may or may not be a bug.

How do I set tabindex to -1 in GWT?

I have this problem with GWT: I need to skip a button from the focus cycle so I set the tab index to -1 with button.setTabIndex(-1), but in the generated html I get tabindex="0"... is this a bug?
It looks like it's on-purpose: FocusWidget's onAttach resets the tab index to 0 in onAttach when it was set to -1: https://gwt.googlesource.com/gwt/+/2.5.1/user/src/com/google/gwt/user/client/ui/FocusWidget.java
This behavior dates back to 3½ years ago (released in GWT 2.1.0): https://code.google.com/p/google-web-toolkit/source/detail?r=7642 so I'm surprised you're the first to report it (that I know of), but it indeed looks like a bug to me.
It seems it is impossible to have a negative tabindex.
At first, the doc of setTabIndex say :
Sets the widget's position in the tab index. If more than one widget
has the same tab index, each such widget will receive focus in an
arbitrary order. Setting the tab index to -1 will cause this widget to
be removed from the tab order.
And w3c say :
Elements that may receive focus should be navigated by user agents
according to the following rules:
Those elements that support the tabindex attribute and assign a positive value to it are navigated first. Navigation proceeds from the
element with the lowest tabindex value to the element with the highest
value. Values need not be sequential nor must they begin with any
particular value. Elements that have identical tabindex values should
be navigated in the order they appear in the character stream.
Those elements that do not support the tabindex attribute or support it and assign it a value of "0" are navigated next. These
elements are navigated in the order they appear in the character
stream.
Elements that are disabled do not participate in the tabbing order.
Source : http://www.w3.org/TR/1999/REC-html401-19991224/interact/forms.html#adef-tabindex
But if you want to skipe your button, try to set the tabindex < -1.
Example :
Button myButton = new Button("Hello");
myButton.setTabIndex(-2);
// "-1" is convert to 0, and the button is not skipped
I try myButton.setTabIndex(-1); and myButton.getElement.setAttribute("tabindex", "-1"), that is always convert to 0 in html.
I wish that help you.
Working with jsni.
For example:
public static native void setElementTabIndex(Element b, int ti)/*-{
b.tabIndex = ti;
}-*/;
//and call the native js function
setElementTabIndex(odButton.getElement(), -1);
As with setFocus, use deferred:
Scheduler.get().scheduleDeferred(new Command() {
#Override
public void execute() {
cb.setTabIndex(-1);
}
});
Where in my case cb = CheckBox()