Я пытаюсь реализовать CellTable с настраиваемым заголовком столбца, который отображает SearchBox (простое текстовое поле) под обычным текстом столбца.
SearchBox должен разрешить пользователю фильтровать CellTable. Он должен выглядеть примерно так:
|Header 1|Header 2 |
|SEARCHBOX|SEARCHBOX|
-------------------------------------------------------
| ROW 1
------------------------------------------------------
| ROW 2
Как только пользователь вводит символ в SearchBox, запускается RangeChangeEvent, который приводит к запросам сервера, а CellTable обновляется с новым фильтрованным списком.
В принципе все работает нормально. Однако, как только CellTable обновляется, SearchBox теряет фокус, и пользователь снова должен щелкнуть мышью в SearchBox, чтобы ввести новый символ.
Это, вероятно, связано с тем, что метод визуализации настраиваемого заголовка и его ячейки вызывается после обновления CellTable.
Есть ли способ вернуть фокус обратно в SearchBox? Я попытался установить tabindex = 0, но это не помогло.
Пользовательский класс заголовка
public static class SearchHeader extends Header<SearchTerm> {
@Override
public void render(Context context, SafeHtmlBuilder sb) {
super.render(context, sb);
}
private SearchTerm searchTerm;
public SearchHeader(SearchTerm searchTerm,ValueUpdater<SearchTerm> valueUpdater) {
super(new SearchCell());
setUpdater(valueUpdater);
this.searchTerm = searchTerm;
}
@Override
public SearchTerm getValue() {
return searchTerm;
}
}
Пользовательская ячейка поиска (используется в пользовательском заголовке)
Булевский флаг isChanged имеет значение true, когда пользователь вводит что-то в SearchBox и возвращается к false, если SearchBox теряет его внимание. Я добавил этот флаг, чтобы отличить, какой SearchBox получает фокус (если я использую несколько SearchBoxes)
public static class SearchCell extends AbstractCell<SearchTerm> {
interface Template extends SafeHtmlTemplates {
@Template("<div style=\"\">{0}</div>")
SafeHtml header(String columnName);
@Template("<div style=\"\"><input type=\"text\" value=\"{0}\"/></div>")
SafeHtml input(String value);
}
private static Template template;
private boolean isChanged = false;
public SearchCell() {
super("keydown","keyup","change","blur");
if (template == null) {
template = GWT.create(Template.class);
}
}
@Override
public void render(com.google.gwt.cell.client.Cell.Context context,
SearchTerm value, SafeHtmlBuilder sb) {
sb.append(template.header(value.getCriteria().toString()));
sb.append(template.input(value.getValue()));
}
@Override
public void onBrowserEvent(Context context,Element parent, SearchTerm value,NativeEvent event,ValueUpdater<SearchTerm> valueUpdater) {
if (value == null)
return;
super.onBrowserEvent(context, parent, value, event, valueUpdater);
if ("keyup".equals(event.getType()))
{
isChanged = true;
InputElement elem = getInputElement(parent);
value.setValue(elem.getValue());
if (valueUpdater != null)
valueUpdater.update(value);
}
else if ("blur".equals(event.getType())) {
isChanged =false;
}
}
protected InputElement getInputElement(Element parent) {
Element elem = parent.getElementsByTagName("input").getItem(0);
assert(elem.getClass() == InputElement.class);
return elem.cast();
}
}
Код инициализации CellTable
NameColumn - это реализация абстрактного класса Column с соответствующими типами. Он использует TextCell внутри.
ValueUpdater<SearchTerm> searchUpdater = new ValueUpdater<SearchTerm>() {
@Override
public void update(AccessionCellTableColumns.SearchTerm value) {
// fires a server request to return the new filtered list
RangeChangeEvent.fire(table, new Range(table.getPageStart(), table.getPageSize()));
}
};
table.addColumn(new NameColumn(searchTerm),new SearchHeader(searchTerm,searchUpdater));