How to auto scroll GWT SuggestBox with max-height

2019-01-23 09:28发布

问题:

How can I auto scroll the GWT SuggestBox with max-height set on the PopupPanel holding the SuggestBox? Currently when the user presses keyboard up keys and down keys styles changes on the suggested items and pressing enter will select the currently selected item on the list.

When the item is located in lower than the max-height scroll bars doesn't scroll. I tried extending the SuggestBox and inner class DefaultSuggestionDisplay to override moveSelectionDown() and moveSelectionUp() to explicitly call popup.setScrollTop().

In order to do this I need access to the absolute top of the currently selected MenuItem therefore need access to SuggestionMenu which is also an inner class of SuggestBox which is private and declared as a private member within DefaultSuggestionDisplay without getter. Since GWT is a JavaScript we can't use reflection to access it.... Does anyone have a workaround for this issue?

Thanks.

回答1:

I've been searching around and couldn't find a proper solution (apart from reimplementing SuggestBox). The following avoids reimplementing SuggestBox:

private static class ScrollableDefaultSuggestionDisplay extends SuggestBox.DefaultSuggestionDisplay {

    private Widget suggestionMenu;

    @Override
    protected Widget decorateSuggestionList(Widget suggestionList) {
        suggestionMenu = suggestionList;

        return suggestionList;
    }

    @Override
    protected void moveSelectionDown() {
         super.moveSelectionDown();
         scrollSelectedItemIntoView();
    }

    @Override
    protected void moveSelectionUp() {
         super.moveSelectionUp();
         scrollSelectedItemIntoView();
    }

    private void scrollSelectedItemIntoView() {
        //                                     DIV          TABLE       TBODY       TR's
        NodeList<Node> trList = suggestionMenu.getElement().getChild(1).getChild(0).getChildNodes();
        for (int trIndex = 0; trIndex < trList.getLength(); ++trIndex) {
            Element trElement = (Element)trList.getItem(trIndex);
            if (((Element)trElement.getChild(0)).getClassName().contains("selected")) {
                trElement.scrollIntoView();

                break;
        }
    }
}

}



回答2:

Following this discussion on Google groups, I implemented a similar solution which is a bit more concise due to the use of JSNI:

private class ScrollableDefaultSuggestionDisplay extends DefaultSuggestionDisplay {

    @Override
    protected void moveSelectionDown() {
        super.moveSelectionDown();
        scrollSelectedItemIntoView();
    }

    @Override
    protected void moveSelectionUp() {
        super.moveSelectionUp();
        scrollSelectedItemIntoView();
    }

    private void scrollSelectedItemIntoView() {
        getSelectedMenuItem().getElement().scrollIntoView();
    }

    private native MenuItem getSelectedMenuItem() /*-{
        var menu = this.@com.google.gwt.user.client.ui.SuggestBox.DefaultSuggestionDisplay::suggestionMenu;
        return menu.@com.google.gwt.user.client.ui.MenuBar::selectedItem;
    }-*/;
}


回答3:

Ok, I finally found the solution. I had to create my own suggest box based on GWT SuggestBox implementations. But follow below in custom implementaion: -Place ScrollPanel to PopupPanel then place MenuBar to ScrollPanel -In moveSelectionUp() and moveSelectionDown() of your new internal SuggestionDisplat implementation add the code below:

 panel.ensureVisible( menu.getSelectedItem( ) );

This is not achievable by extending the SuggestBox since we won't have access to selected MenuItem unless overriding protected getSelectionItem() method as public method.

Finally add CSS:

max-height: 250px;

To the popupPanel in your display implementations.