EXT-GWT (GXT) Display Icon and Text for displayfield in Combobox - gwt

Does anyone know how to display an Icon and a Text for the displaying field in ext-gwts combobo? I tried everything.
In the third ComboBox of this example (klick me) there is an icon and the text for the selectable values. This was no problem with the example template. But i want to show the icon and the text for the selected value too. How can i manage this?
I have a Model class for the icon and the text.
public class Language extends DbBaseObjectModel {
private static final long serialVersionUID = 8477520184310335811L;
public Language(String langIcon, String langName) {
setLangIcon(langIcon);
setLangName(langName);
}
public String getLangIcon() {
return get("langIcon");
}
public String getLangName() {
return get("langName");
}
public void setLangIcon(String langIcon) {
set("langIcon", langIcon);
}
public void setLangName(String langName) {
set("langName", langName);
}
}
This is how i initalize the ComboBox. I want to change the displayField "langName".
final ListStore<Language> countries = new ListStore<Language>();
final Language german = new Language("de_DE", "Deutsch");
final Language english = new Language("en_GB", "Englisch");
countries.add(german);
countries.add(english);
final ComboBox<Language> combo = new ComboBox<Language>();
combo.setWidth(100);
combo.setStore(countries);
combo.setDisplayField("langName");
combo.setTemplate(getFlagTemplate());
combo.setTypeAhead(true);
combo.setTriggerAction(TriggerAction.ALL);
combo.setValue(german);
This is the template for the ComboBox two show the selectable values.
private native String getFlagTemplate() /*-{
return [ '<tpl for=".">', '<div class="x-combo-list-item">',
'<img src="resources/images/lang/{langIcon}.png">',
' {langName}</div>', '</tpl>' ].join("");
}-*/;
How can i use an template for the displayField or is there an other possibility?
Thanks!

You need to implement a com.extjs.gxt.ui.client.widget.form.ListModelPropertyEditor.
The com.extjs.gxt.ui.client.widget.form.PropertyEditor#getStringValue returns the string that should be displayed and the com.extjs.gxt.ui.client.widget.form.PropertyEditor#convertStringValue converts the displayed string back into the model.
This isn't a very performant implementation but it works:
public class TemplateModelPropertyEditor<D extends ModelData> extends
ListModelPropertyEditor<D> {
/** Template to render the model. */
private XTemplate template;
#Override
public D convertStringValue(final String value) {
for (final D d : models) {
final String val = getStringValue(d);
if (value.equals(val)) {
return d;
}
}
return null;
}
#Override
public String getStringValue(final D value) {
if (template != null) {
final Element div = DOM.createDiv();
template.overwrite(div, Util.getJsObject(value));
return div.getInnerText();
}
final Object obj = value.get(displayProperty);
if (obj != null) {
return obj.toString();
}
return null;
}
public void setSimpleTemplate(final String html) {
template = XTemplate.create(html);
}
}
Usage:
TemplateModelPropertyEditor<Language> propertyEditor = new TemplateModelPropertyEditor<Language>();
propertyEditor.setSimpleTemplate(getFlagTemplate());
combo.setPropertyEditor(propertyEditor);

which imports?
I added these ones:
import com.extjs.gxt.ui.client.core.XTemplate;
import com.extjs.gxt.ui.client.util.Util;
import com.extjs.gxt.ui.client.widget.form.ListModelPropertyEditor;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.Element;
Everthing works fine, but it don't display an icon. When i debug the return div.getInnerText() method throws an error called: Method "getInnerText" with signature "()Ljava/lang/String;" is not applicable on this object.
The created div element looks okay
<DIV><DIV class=x-combo-list-item><IMG src="http://127.0.0.1:8888/resources/images/lang/de_DE.png"> Deutsch</DIV></DIV>

Related

GWT celltable. How to set cell css style after changing value in EditTextCell

Base on user's entry in editable cell I would like to display concrete style. What I am trying to do is a very base validation.
I've tried already override getCellStyleNames in Anonymous new Column() {}, but this work on start, base on model values, but what would work, after user change value of that cell?
Please help.
You're very close.
Override getCellStyleNames in the new Column() {} is the first half of the solution.
The second half:
yourColumn.setFieldUpdater(new FieldUpdater<DataType, String>() {
#Override
public void update(int index, DataType object, String value) {
// the following line will apply the correct css
// based on the current cell value
cellTable.redrawRow(index);
}
});
Hope this would help!
The following code is a trivia but complete example.
A celltable with two column is defined. Each cell in the first column displays a simple question. Each cell in the second column is an editable cell which allows you to enter you answer to the question shown in first column. If your answer is correct, then the text of the answer will be styled as bold and black. Otherwise, the text will be styled as red in normal font weight.
Source code of the trivia GWT app:
import com.google.gwt.cell.client.Cell;
import com.google.gwt.cell.client.EditTextCell;
import com.google.gwt.cell.client.FieldUpdater;
import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.user.cellview.client.CellTable;
import com.google.gwt.user.cellview.client.Column;
import com.google.gwt.user.cellview.client.TextColumn;
import com.google.gwt.user.client.ui.RootPanel;
import java.util.Arrays;
import java.util.List;
public class CellTableExample implements EntryPoint {
private static class Question {
private final String question;
private final String correctAnswer;
private String userProvidedAnswer;
public Question(String question, String correctAnswer) {
this.question = question;
this.correctAnswer = correctAnswer;
this.userProvidedAnswer = "";
}
public String getQuestion() {
return question;
}
public String getCorrectAnswer() {
return correctAnswer;
}
public String getUserProvidedAnswer() {
return userProvidedAnswer;
}
public void setUserProvidedAnswer(String userProvidedAnswer) {
this.userProvidedAnswer = userProvidedAnswer;
}
}
private static final List<Question> questionList = Arrays.asList(
new Question("Which city is capital of England?", "London"),
new Question("Which city is capital of Japan?", "Tokyo"));
#Override
public void onModuleLoad() {
final CellTable<Question> cellTable = new CellTable<>();
TextColumn<Question> questionCol = new TextColumn<Question>() {
#Override
public String getValue(Question object) {
return object.getQuestion();
}
};
Column<Question, String> ansCol = new Column<Question, String>(new EditTextCell()) {
#Override
public String getValue(Question object) {
return object.getUserProvidedAnswer();
}
#Override
public String getCellStyleNames(Cell.Context context, Question object) {
if (object.getUserProvidedAnswer().equalsIgnoreCase(object.getCorrectAnswer())) {
return "correct-answer";
} else {
return "wrong-answer";
}
}
};
ansCol.setFieldUpdater(new FieldUpdater<Question, String>() {
#Override
public void update(int index, Question object, String value) {
object.setUserProvidedAnswer(value);
cellTable.redrawRow(index);
}
});
cellTable.addColumn(questionCol, "Question");
cellTable.addColumn(ansCol, "Your Answer");
cellTable.setRowData(0, questionList);
RootPanel.get().add(cellTable);
}
}
Companion css file:
.correct-answer {
font-weight: bold;
color: black;
}
.wrong-answer {
font-weight: normal;
color: red;
}
Screenshot1: Right after the app started. The column of answers was empty.
Screenshot2: After I entered answers. Apparently I answered the first one correctly but not the second one.
Use setCellStyleNames inside the render method:
Column<MyType, String> testColumn = new Column<MyType, String>(new EditTextCell()) {
#Override
public String getValue(MyType object) {
return object.getValue();
}
#Override
public void render(Context context, MyType object, SafeHtmlBuilder sb) {
if(object.isValid())
setCellStyleNames("validStyleNames");
else
setCellStyleNames("invalidStyleNames");
super.render(context, object, sb);
}
};
Correct aproach is to overide getCellStyleNames method in anonymous class:
new Column<Model, String>(new EditTextCell())
You have to return string name of css class.

GXT 3 GridRowEditing SimpleComboBox entries not displayed

i'm currently using a GXT3 grid to display data from a custom object EntityDAO.
This class contains 3 attributes: an id and two references to complex type objects
Let's call them
Long id;
UserInfo userInfo;
OutputInfo outputInfo;
I created an interface to explicit the desired display of these info:
interface EntityDAOProperties extends PropertyAccess<EntityDAO> {
ModelKeyProvider<EntityDAO> id();
#Path("userInfo.name")
ValueProvider<EntityDAO, String> step();
#Path("outputInfo.name")
ValueProvider<EntityDAO, String> outputInfo();
}
The display is perfectly fine. The matter is that i want to be able to add/edit rows to my grid.
To do so, I have a
GridRowEditing<EntityDAO> editing = createGridEditing(grid);
comprising a
SimpleComboBox<String> comboUser = new SimpleComboBox<String>(new LabelProvider<String>() {
#Override
public String getLabel(String item) {
return item;
}
});
for(...){
comboUser.add("entry " + i); // For instance
logger.info("entry : " +i); // For instance
i++;
}
comboUser.setEditable(false);
comboUser.setTriggerAction(TriggerAction.ALL);
When i double click on my line and make the GridRowEditing appear, the combo doesn't seem to have more than 1 row and the click on the expand arrow doesn't change anything to the matter.
I think you miss the part where you set the property editor for the combobox, here is the example code:
SimpleComboBox<Light> combo = new SimpleComboBox<Light>(new StringLabelProvider<Light>());
combo.setClearValueOnParseError(false);
combo.setPropertyEditor(new PropertyEditor<Light>() {
#Override
public Light parse(CharSequence text) throws ParseException {
return Light.parseString(text.toString());
}
#Override
public String render(Light object) {
return object == null ? Light.SUNNY.toString() : object.toString();
}
});
combo.setTriggerAction(TriggerAction.ALL);
combo.add(Light.SUNNY);
combo.add(Light.MOSTLYSUNNY);
combo.add(Light.SUNORSHADE);
combo.add(Light.MOSTLYSHADY);
combo.add(Light.SHADE);
// combo.setForceSelection(true);
editing.addEditor(cc2, new Converter<String, Light>() {
#Override
public String convertFieldValue(Light object) {
return object == null ? "" : object.toString();
}
#Override
public Light convertModelValue(String object) {
try {
return Light.parseString(object);
} catch (ParseException e) {
return null;
}
}
}, combo);
Hope this could help you.

How to add a generic "All" value in GXT ComboBox

I have a generic GXT3 ComboBox which display all available values for enums :
public static <T extends Enum<T>> ComboBox<T> buildEnumCombo(Class<T> t){
ListStore<T> listStore=new ListStore<T>(new EnumModelKeyProvider<T>());
for(T e:t.getEnumConstants()){
listStore.add(e);
}
ComboBox<T> combo= new ComboBox<T>(listStore, new EnumLabelProvider<T>());
combo.setTriggerAction(ComboBoxCell.TriggerAction.ALL);
return combo;
}
This combo works fine.
What I need : I would like a be able to add a "All" value.
I tried to add "null" in the store and customize the LabelProvider to display "All" for this particular case but it does not work as expected : the combo contains the expected line but it displays an empty text instead of "All" and the line does not have a correct size.
Here is my generic ModelKeyProvider for enums
public class EnumModelKeyProvider<T extends Enum> implements ModelKeyProvider<T> {
#Override
public String getKey(T item) {
if(item==null){
return null;
}else{
return item.name();
}
}
And my generic LabelProvider :
public class EnumLabelProvider<T extends Enum<T>> implements LabelProvider<T> {
#Override
public String getLabel(T item) {
if(item==null){
return "All";
}else{
return I18nEnum.i18nEnum(item);
}
}
}
Maybe not the solution you are looking for, but I solved this but simply setting the emptyText of the ComboBox to "All".
Try SimpleComboBox (tested on gxt 2.2.5)
private SimpleComboBox<String> createSimpleComboBox(){
SimpleComboBox<String> combo = new SimpleComboBox<String>();
combo.setTypeAhead(true);
combo.setTriggerAction(TriggerAction.ALL);
combo.setEditable(editable);
combo.setForceSelection(true);
combo.setTemplate(getComboTemplate());
return combo;
}
private native String getComboTemplate() /*-{
return [
'<tpl for=".">',
'<tpl if="value == \'\'">',
'<div class="x-combo-list-item" qtip="N/A" qtitle=""></BR></div>',
'</tpl>',
'<tpl if="value != \'\'">',
'<div class="x-combo-list-item" qtip="{value}" qtitle="">{value}</div>',
'</tpl>',
'</tpl>'
].join("");
}-*/;
public SimpleComboBox<String> buildComboBox(){
SimpleComboBox<String> combo = createSimpleComboBox();
combo.add("");
List<String> list = new ArrayList<String>();
for(T e:t.getEnumConstants()){
list.add(e.name());
}
combo.add(list);
return combo;
}

SuggestBox override addSelectionHandler

I have a custom Oracle with Objects to pass to the SuggestBox. Then I need get back a object when it's selected from de SuggestBox.
public HandlerRegistration addSelectionHandler(SelectionHandler<SuggestOracle.Suggestion> handler)
The problem is that I don't have Suggestion. I have "CustomSuggestion". I read de API and I try to write a Custom SuggestBox implementing the interface HasSelectionHandlers but I can't because the SuggestBox have a implementation of the interface. I get the error:
The interface HasSelectionHandlers cannot be implemented more than once with different arguments: HasSelectionHandlers<SuggestOracle.Suggestion> and HasSelectionHandlers<CustomSuggestion>
Can you help me? Sorry for my bad english.
Not sure I understand your problem. Have a look at the following example (really basic but you should get an idea on how to deal with custom suggestions). Hope that helps:
public void onModuleLoad() {
SuggestBox box = new SuggestBox(new CustomOracle<CustomSuggestion>());
box.addSelectionHandler(new SelectionHandler<SuggestOracle.Suggestion>() {
#Override
public void onSelection(SelectionEvent<Suggestion> event) {
String value = ((CustomSuggestion) event.getSelectedItem()).fSomeOtherValue;
Window.alert(value);
}
});
RootPanel.get().add(box);
}
private class CustomOracle<CustomSuggestion> extends SuggestOracle {
private LinkedList<Starter.CustomSuggestion> fStore;
public CustomOracle() {
fStore = new LinkedList<Starter.CustomSuggestion>();
fStore.add(new Starter.CustomSuggestion("2", "two", "foo"));
fStore.add(new Starter.CustomSuggestion("22", "twenty-two", "bar"));
fStore.add(new Starter.CustomSuggestion("222", "two-hundred twenty-two", "w000t"));
}
#Override
public void requestSuggestions(Request request, Callback callback) {
String query = request.getQuery();
LinkedList<Starter.CustomSuggestion> result = new LinkedList<Starter.CustomSuggestion>();
for (Starter.CustomSuggestion entry : fStore) {
if (entry.fDisplay.contains(query)) {
result.add(entry);
}
}
callback.onSuggestionsReady(request, new Response(result));
}
}
private class CustomSuggestion implements Suggestion {
private String fReplace;
private String fDisplay;
private String fSomeOtherValue;
public CustomSuggestion(String display, String replace, String someOtherValue) {
fDisplay = display;
fReplace = replace;
fSomeOtherValue = someOtherValue;
}
#Override
public String getDisplayString() {
return fDisplay;
}
#Override
public String getReplacementString() {
return fReplace;
}
}

How do I add items to GWT ListBox in Uibinder .ui.xml template ?

How to add the listbox items using UiBinder?
It is possible since february 2011 version:
http://code.google.com/p/google-web-toolkit/issues/detail?id=4654
Following this patch you are now able to add items following this syntax:
<g:ListBox>
<g:item value='1'>
first item
</g:item>
<g:item value='2'>
second item
</g:item>
</g:ListBox>
This is a listbox of translations of an enumeration, I suppose this also works for a listbox with string values (version of GWT: 2.1.0)
You only need the renderer for translating the enumeration values.
//UI XML
<g:ValueListBox ui:field="requesterType"/>
//JAVA CODE
#UiField(provided = true)
ValueListBox<RequesterType> requesterType = new ValueListBox<RequesterType>(requesterTypeRenderer);
static EnumRenderer<RequesterType> requesterTypeRenderer = new EnumRenderer<RequesterType>();
public Constructor() {
requesterTypeRenderer.setEmptyValue(Translations.translateEmptyValue(RequesterType.class));
requesterType.setAcceptableValues(Arrays.asList(EnumUtil.getRequesterTypes()));
}
/**
* Translates enum entries. Use setEmptyValue() if you want to have a custom empty value. Default empty value is "".
*
* #param <T>
* an enumeration entry which is to be registered in {#link Translations}
*/
public class EnumRenderer<T extends Enum<?>> extends AbstractRenderer<T> {
private String emptyValue = "";
#Override
public String render(T object) {
if (object == null)
return emptyValue;
return Translations.translate(object);
}
public void setEmptyValue(String emptyValue) {
this.emptyValue = emptyValue;
}
}
GWT ValueListbox otherwise know as a ComboBox or Dropdown component.
Another example that also demonstrates populating the list.
UiBinder...
<g:ValueListBox ui:field="subCategory"/>
Editor...
#UiField(provided = true)
ValueListBox<String> subCategory = new ValueListBox<String>(
new Renderer<String>() {
#Override
public String render(String object) {
String s = "Cats";
if (object != null) {
s = object.toString();
}
return s;
}
#Override
public void render(String object, Appendable appendable)
throws IOException {
render(object);
}
});
Constructor...
List<String> values = new ArrayList<String>();
values.add("Animal Shelters and Rescues");
values.add("Birds");
values.add("Cats");
values.add("Dogs");
values.add("Other Pets");
values.add("Rabbits");
subCategory.setAcceptableValues(values);