Search code examples
javagwtgxt

GXT Combobox with unselectable categories


I am trying to do a ComboBox with options and categories in GXT 3.

I can use a ComboBoxCell to have a different display for options and categories.

Problem : I need the categories to be unselectable (like with HTML tag <optgroup>).

Here is a plain old HTML comboBox (<select> tag)

HTML CODE:

<!DOCTYPE html>
<html>
  <head>

  </head>
  <body>
    <select>
      <optgroup label="category 1">
        <option name="option1">Option 1</option>
        <option name="option2">Option 2</option>
        <option name="option3">Option 3</option>
      </optgroup>
      <optgroup label="category 2">
        <option name="option4">Option 4</option>
        <option name="option5">Option 5</option>
        <option name="option6">Option 6</option>
      </optgroup>
    </select>
  </body>
</html>

As you may see on this fiddle, it produces a ComboBox with unselectable categories. I am trying to do the equivalent with GXT.

Any idea?

EDIT:

I finally did my own implementation :

import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.Element;
import com.google.gwt.user.client.ui.UIObject;
import com.google.gwt.user.client.ui.Widget;

import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;

public class Select<T>  extends Widget {

  private static final String TAG_OPTGROUP = "optgroup";
  private static final String ATTR_NAME = "name";
  private static final String PROPERTY_SELECTED = "selected";

  private Element select;
  private Map<Element, T> mapElement;

  public Select(boolean multiple){
    this.mapElement=new HashMap<Element, T>();
    this.select = DOM.createSelect(multiple);
    this.setElement(this.select);
  }

  public Select(){
    this(false);
  }

  public OptGroup addGroup(String displayName){
    OptGroup optGroup=new OptGroup(displayName);
    this.select.appendChild(optGroup.getElement());
    return optGroup;
  }

  public void addOption(T t,String displayName){
    Element option=DOM.createOption();
    option.setAttribute(ATTR_NAME,t.toString());
    option.setInnerText(displayName);
    this.select.appendChild(option);
    this.mapElement.put(option,t);
  }

  public T getSelectedValue(){
    for(Map.Entry<Element,T> entry:mapElement.entrySet()){
      if(entry.getKey().getPropertyBoolean(PROPERTY_SELECTED)){
        return entry.getValue();
      }
    }
    return null;
  }

  public Collection<T> getSelectedValues(){
    Collection<T> result=new HashSet<T>();
    for(Map.Entry<Element,T> entry: mapElement.entrySet()){
      if(entry.getKey().getPropertyBoolean(PROPERTY_SELECTED)){
        result.add(entry.getValue());
      }
    }
    return result;
  }

  public class OptGroup extends UIObject {
    private static final String ATTR_LABEL="label";

    private String name;
    private Element element;

    private OptGroup(String name) {
      this.name = name;
      this.element = DOM.createElement(TAG_OPTGROUP);
      this.element.setAttribute(ATTR_LABEL,name);
      this.setElement(this.element);
    }

    public String getName() {
      return name;
    }

    public void addOption(T t,String displayName){
      Element option=DOM.createOption();
      option.setAttribute(ATTR_NAME,t.toString());
      option.setInnerText(displayName);
      this.element.appendChild(option);
      mapElement.put(option,t);
    }
  }
}

This is perfectible as I use toString() for the attribute name of the <option> tag but it meets my need ;)


Solution

  • I think gwt list box doesn't support optgroup. You will have to use the DOM API. Something like this would do

    List<String> options = new ArrayList<String>();
    options.add("Option 1");
    options.add("Option 2");
    options.add("Option 3");
    
    ListBox combo = new ListBox();
    SelectElement selectElm = combo.getElement().cast();
    OptGroupElement groupElement =Document.get().createOptGroupElement();
    groupElement.setLabel("category 1");
    
    for (String option : options) 
    {
        OptionElement optElement = Document.get().createOptionElement();
        optElement.setInnerText(option.getName());
        groupElement.appendChild(optElement);
    }
    
    selectElm.appendChild(groupElement);