public Comboitem newComboitem(Combobox combobox) { // clone from template final Comboitem clone = (Comboitem) _template.clone(); // TODO: see if databinder has this kind of Comboitem, if not, add new CollectionListItem // avoid duplicate id error, will set to new id when render() // Bug #1962153: Data binding generates duplicate id in some case add "_". if (clone.getId().length() > 0) { clone.setId(null); } // link cloned component with template // each Comboitem and and it descendants share the same templatemap Map<Object, Object> templatemap = new HashMap<Object, Object>(8); BindingRendererUtil.linkTemplates(clone, _template, templatemap, _binder); // link this template map to parent templatemap (Combobox in Combobox) Map parenttemplatemap = (Map) combobox.getAttribute(DataBinder.TEMPLATEMAP); if (parenttemplatemap != null) { templatemap.put(DataBinder.TEMPLATEMAP, parenttemplatemap); } // kept clone kids somewhere to avoid create too many components in browser final List<Component> kids = new ArrayList<Component>(clone.getChildren()); clone.setAttribute(KIDS, kids); clone.getChildren().clear(); return clone; }
public void render(final Comboitem item, final Object data, final int index) throws Exception { final Combobox cb = (Combobox) item.getParent(); final ListModel<?> model = cb.getModel(); final int size = model.getSize(); final Template tm = resoloveTemplate(cb, item, data, index, size, "model"); if (tm == null) { item.setLabel(Objects.toString(data)); item.setValue(data); } else { final ForEachStatus iterStatus = new AbstractForEachStatus() { // provide iteration status in this context private static final long serialVersionUID = 1L; public int getIndex() { return index; } public Object getEach() { return data; } public Integer getEnd() { return size; } }; final String var = (String) tm.getParameters().get(EACH_ATTR); final String varnm = var == null ? EACH_VAR : var; // var is not specified, default to "each" final String itervar = (String) tm.getParameters().get(STATUS_ATTR); final String itervarnm = itervar == null ? (var == null ? EACH_STATUS_VAR : varnm + STATUS_POST_VAR) : itervar; // provide default value if not specified // bug 1188, EL when nested var and itervar Object oldVar = cb.getAttribute(varnm); Object oldIter = cb.getAttribute(itervarnm); cb.setAttribute(varnm, data); cb.setAttribute(itervarnm, iterStatus); final Component[] items = tm.create(cb, item, null, null); cb.setAttribute(varnm, oldVar); cb.setAttribute(itervarnm, oldIter); if (items.length != 1) throw new UiException("The model template must have exactly one item, not " + items.length); final Comboitem nci = (Comboitem) items[0]; nci.setAttribute(BinderImpl.VAR, varnm); // for the converter to get the value if (model instanceof ListSubModel) { // ZK-992 wrong item when binding to combbox with submodel implementation // combobox has a internal model as the submodel, // I don't have way to access the submodel, and user doesn't has info to notify model[index] // changed. // so I set the value directly. nci.setAttribute(varnm, data); } else { addItemReference( cb, nci, index, varnm); // kept the reference to the data, before ON_BIND_INIT } nci.setAttribute(itervarnm, iterStatus); // add template dependency addTemplateTracking(cb, nci, data, index, size); if (nci.getValue() == null) // template might set it nci.setValue(data); item.setAttribute("org.zkoss.zul.model.renderAs", nci); // indicate a new item is created to replace the existent one item.detach(); // bug #ZK-677: combobox selection is lost after reload model // binding Comboitem immediately, @see BindUiLifeCycle#afterComponentAttached Events.sendEvent(new Event(BinderImpl.ON_BIND_INIT, nci)); } }