1

Databinding and auto-complete on combobox

asked 2011-02-09 03:04:18 +0800

SerFingolfin gravatar image SerFingolfin
70 2

updated 2013-06-26 07:51:25 +0800

jimyeh gravatar image jimyeh
2047 1 4
ZK Team

Hi to everybody.
As shown in zk demo, it's easy to obtain a combobox with auto-complete function.
Is it possible to have auto-complete comboboxes with databinding?
Something like:

<combobox model="${weeklyModel}" selectedItem="@{selected.timeRange.end}"
  value="@{selected.timeRange.end, converter='PartialTypeConverter'}"
  readonly="true">
  <comboitem self="@{each=endd}" 
    label="@{endd, converter='PartialTypeConverter'}" 
    value="@{endd}"/>
</combobox>

With auto-completion based on a object-specific field of the model's object collection.
Can i reach that?
Thanks in advance.

delete flag offensive retag edit

11 Replies

Sort by ยป oldest newest

answered 2011-02-22 04:25:48 +0800

jimmyshiau gravatar image jimmyshiau
4921 5
http://www.zkoss.org/ ZK Team

Hi SerFingolfin,
No support yet,
The auto complete has to implement the ListSubModel interface,
and the data binding has to implement the BindingListModel interface,
You can post a feature request here.

link publish delete flag offensive edit

answered 2011-10-12 22:55:16 +0800

arscek gravatar image arscek
21

Hello, I'm new to ZK and I'm loving it so far. I'd like to know if I can use the autocomplete function with a list of beans e.g. Product and select some specific value like the ID and display the Description on the label. I've found a lot of examples, but they are made with strings or numbers or databinding, and I only need an autocomplete combobox to display desc and save its corresponding id. I'm sorry if I'm posting this in the wrong place.

link publish delete flag offensive edit

answered 2011-10-12 23:31:07 +0800

jimmyshiau gravatar image jimmyshiau
4921 5
http://www.zkoss.org/ ZK Team

Hi arscek,
I have created a sample,

ZKFiddle-Link

MyItem.java
package j25jldcg$v1;

public class MyItem {
private int id;
private String name;

public MyItem(int id, String name) {
super();
this.id = id;
this.name = name;
}

public String getName() {
return name;
}

public int getId() {
return id;
}
public String toString() {
return id+": "+name;
}

}


TestComposer.java
package j25jldcg$v1;

import org.zkoss.zk.ui.*;
import org.zkoss.zk.ui.event.*;
import org.zkoss.zk.ui.util.*;
import org.zkoss.zk.ui.ext.*;
import org.zkoss.zk.au.*;
import org.zkoss.zk.au.out.*;
import org.zkoss.zul.*;
import java.util.*;

public class TestComposer extends GenericForwardComposer{

private Label msg;
private Combobox cb;

public void doBeforeComposeChildren(Component comp) throws Exception {
super.doBeforeComposeChildren(comp);
String[] _dict = {
"abacus", "accuracy", "acuity", "adage", "afar", "after", "apple",
"bible", "bird", "bingle", "blog",
"cabane", "cape", "cease", "cedar",
"dacron", "defacto", "definable", "deluxe",
"each", "eager", "effect", "efficacy",
"far", "far from",
"girl", "gigantean", "giant",
"home", "honest", "huge",
"information", "inner",
"jump", "jungle", "jungle fever",
"kaka", "kale", "kame",
"lamella", "lane", "lemma",
"master", "maxima", "music",
"nerve", "new", "number",
"omega", "opera",
"pea", "peace", "peaceful",
"rock", "RIA",
"sound", "spread", "student", "super",
"tea", "teacher",
"unit", "universe",
"vector", "victory",
"wake", "wee", "weak", "web2.0",
"xeme",
"yea", "yellow",
"zebra", "zk",

};




List list = new ArrayList();
for (int i = 0; i < _dict.length; i++)
list.add(new MyItem(i, _dict[i]));

comp.setAttribute("dictModel", new SimpleListModel(list) {
protected boolean inSubModel(Object key, Object value) {
String idx = key.toString();
MyItem myItem = (MyItem)value;
return idx.length() > 0 && myItem.getName().startsWith(idx);
}
});


comp.setAttribute("renderer",new ComboitemRenderer () {
public void render(Comboitem item, Object data) throws Exception {
MyItem myItem = (MyItem)data;
item.setLabel(myItem.getName());
item.setValue(myItem);
}
});

}

public void onSelect$cb() {
msg.setValue(cb.getSelectedItem().getValue().toString());
}
}


index.zul
<zk>
<window border="normal" title="Auto-complete" apply="j25jldcg$v1.TestComposer">
<combobox model="${dictModel}" itemRenderer="${renderer}" id="cb" autodrop="true"/>
<label id="msg"/>
</window>
</zk>

link publish delete flag offensive edit

answered 2013-06-17 14:28:28 +0800

Senthilchettyin gravatar image Senthilchettyin flag of India
2623 3 8
http://emrpms.blogspot.in...

Hi jimmyshiau

Can you please give me MVVM Version of the above example code ?

Regards Senthil

link publish delete flag offensive edit

answered 2013-06-19 10:32:19 +0800

Senthilchettyin gravatar image Senthilchettyin flag of India
2623 3 8
http://emrpms.blogspot.in...

Any help please

link publish delete flag offensive edit

answered 2013-06-22 09:08:47 +0800

Senthilchettyin gravatar image Senthilchettyin flag of India
2623 3 8
http://emrpms.blogspot.in...

Any help please.....................

link publish delete flag offensive edit

answered 2013-06-24 08:01:23 +0800

benbai gravatar image benbai
2228 6
http://www.zkoss.org

To use ListSubModel with Java Beans, you need to provide appropriate Comparator.

simple sample:

test.zul

<zk>
    <div apply="org.zkoss.bind.BindComposer" 
        viewModel="@id('vm') @init('test.TestVM')">
        <combobox model="@load(vm.model)" autodrop="true"
            autocomplete="true">
            <template name="model">
                <comboitem label="@load(each.label)" description="@load(each.desc)" />
            </template>
        </combobox>
    </div>
</zk>

TestVM.java

package test;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;

import org.zkoss.zul.ListModel;
import org.zkoss.zul.ListModelList;
import org.zkoss.zul.ListModels;

/**
 * tested with ZK 6.5.2
 * 
 * @author benbai
 *
 */
@SuppressWarnings({ "rawtypes", "unchecked" })
public class TestVM {
    ListModelList _model;

    public ListModel getModel () {
        if (_model == null) {
            List l = new ArrayList();
            l.add(new Data("Item 1", "Desc 1"));
            l.add(new Data("Item 2", "Desc 2"));
            l.add(new Data("Object 1", "ObjDesc 1"));
            l.add(new Data("Object 2", "ObjDesc 2"));
            _model = new ListModelList(l);
        }
        return ListModels.toListSubModel(_model, getComparator(), 25);
    }

    private Comparator getComparator () {
        return new Comparator () {
            public int compare (Object o1, Object o2) {
                if (o1 == null) return -1;
                Data d2 = (Data)o2;
                if (o1 instanceof String) {
                    String s1 = (String)o1;
                    if (s1 == null || s1.isEmpty())
                        return -1;
                    return d2.getLabel().startsWith(s1)?
                            0 : s1.compareTo(d2.getLabel());
                } else if (o1 instanceof Data) {
                    Data d1 = (Data)o1;
                    return d1.getLabel().compareTo(d2.getLabel());
                }
                return -1;
            }
        };
    }
    public static class Data {
        String _label;
        String _desc;
        public Data (String label, String desc) {
            _label = label;
            _desc = desc;
        }
        public String getLabel () {
            return _label;
        }
        public String getDesc () {
            return _desc;
        }
    }
}
link publish delete flag offensive edit

answered 2013-07-03 10:08:26 +0800

Senthilchettyin gravatar image Senthilchettyin flag of India
2623 3 8
http://emrpms.blogspot.in...

Thank you benbai. Can i use this for the table which contains more than 30,000 records ?.

Or do you have any other suggestion ?

link publish delete flag offensive edit

answered 2013-07-05 05:59:58 +0800

benbai gravatar image benbai
2228 6
http://www.zkoss.org

updated 2013-07-05 06:02:53 +0800

For 30000 records is okay I think, you can also try implement ListSubModel by your self to get live data from DB directly instead of put all data in memory (trade off: probably increase the processing time). Or you can try keep a static list as the data provider and fetch data from it dynamically.

e.g., the updated TestVM.java, keep only selection in memory

package test;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import org.zkoss.zul.ListModel;
import org.zkoss.zul.ListModelList;
import org.zkoss.zul.ListSubModel;
import org.zkoss.zul.event.ListDataListener;
import org.zkoss.zul.ext.Selectable;

/**
 * tested with ZK 6.5.2
 * 
 * @author benbai
 *
 */
@SuppressWarnings({ "rawtypes", "unchecked" })
public class TestVM {

    public ListModel getModel () {
        return new CustomSubModel(false);
    }

    public static class CustomSubModel<E> implements ListModel<E>, ListSubModel<E>, 
        Selectable<E>, java.io.Serializable {
        private boolean _multiple;
        private Set _selection = new HashSet();
        private ListModelList<E> _model = new ListModelList(new ArrayList(), true);;

        public CustomSubModel (boolean multiple) {
            _multiple = multiple;
        }
        public ListModel getSubModel(java.lang.Object value, int nRows) {
            Set oldSelection = null;
            Set newSelection = new HashSet();
            List datas = new ArrayList();
            if (value != null && !value.toString().isEmpty()) {
                // dynamically create data
                // assume fetch data from DB here
                for (int i = 0; i < 5; i++) {
                    datas.add(new Data(value.toString() + "__" + i, value.toString() + "Desc__" + i));
                }
            }
            if (_model != null) {
                // join current selection
                oldSelection = _model.getSelection();
                _selection.addAll(oldSelection);
            }

            for (Object o : _selection) {
                Data d = (Data)o;
                if (datas.contains(o)) {
                    newSelection.add(o);
                }
            }
            final Selectable model =  new ListModelList(datas, true);
            model.setMultiple(_multiple);
            model.setSelection(newSelection);
            _model = (ListModelList)model;
            return (ListModel)model;
        }
        public E getElementAt(int index) {
            return _model.getElementAt(index);
        }

        public int getSize() {
            return _model.getSize();
        }

        public void addListDataListener(ListDataListener l) {
            _model.addListDataListener(l);
        }

        public void removeListDataListener(ListDataListener l) {
            _model.removeListDataListener(l);
        }

        @SuppressWarnings("unchecked")
        private Selectable<E> getSelectModel() {
            return (Selectable<E>) _model;
        }

        public Set<E> getSelection() {
            return getSelectModel().getSelection();
        }


        public void setSelection(Collection<? extends E> selection) {
            getSelectModel().setSelection(selection);
        }


        public boolean isSelected(Object obj) {
            return getSelectModel().isSelected(obj);
        }


        public boolean isSelectionEmpty() {
            return getSelectModel().isSelectionEmpty();
        }


        public boolean addToSelection(E obj) {
            return getSelectModel().addToSelection(obj);
        }


        public boolean removeFromSelection(Object obj) {
            return getSelectModel().removeFromSelection(obj);
        }


        public void clearSelection() {
            getSelectModel().clearSelection();

        }


        public void setMultiple(boolean multiple) {
            getSelectModel().setMultiple(multiple);

        }


        public boolean isMultiple() {
            return getSelectModel().isMultiple();
        }
    }
    public static class Data {
        String _label;
        String _desc;
        public Data (String label, String desc) {
            _label = label;
            _desc = desc;
        }
        public String getLabel () {
            return _label;
        }
        public String getDesc () {
            return _desc;
        }
        public boolean equals (Object o) {
            if (o != null && (o instanceof Data)) {
                Data d = (Data)o;
                return d.getLabel().equals(_label)
                    && d.getDesc().equals(_desc);
            }
            return false;
        }
    }
}

For more information, please refer to the code:

ListModels.java

link publish delete flag offensive edit

answered 2013-07-06 14:57:14 +0800

Senthilchettyin gravatar image Senthilchettyin flag of India
2623 3 8
http://emrpms.blogspot.in...

Again thanks benbai. The first options seems to be ok in my project. But how we can validate if the user enter the value if that is not in the list ?

Can we have selecteditem property, and in that case, it will be null ? Please let me know.

link publish delete flag offensive edit
Your reply
Please start posting your answer anonymously - your answer will be saved within the current session and published after you log in or create a new account. Please try to give a substantial answer, for discussions, please use comments and please do remember to vote (after you log in)!

[hide preview]

Question tools

Follow
2 followers

RSS

Stats

Asked: 2011-02-09 03:04:18 +0800

Seen: 1,245 times

Last updated: Jul 08 '13

Support Options
  • Email Support
  • Training
  • Consulting
  • Outsourcing
Learn More