I'm using JSF 2.2 with Prime Faces 5.3.
I'm trying to create an html5 component with dynamic options. The goal is to create something similar to the f:selectItems tag
At the moment I've the following code(datalist.xhtml file) for the datalist tag
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html>
<html xmlns:cc="http://xmlns.jcp.org/jsf/composite">
<cc:interface></cc:interface>
<cc:implementation>
<datalist id="#{cc.attrs.id}">
<cc:insertChildren/>
</datalist>
</cc:implementation>
</html>
and the following for the single option(option.xhtml file)
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html>
<html xmlns:cc="http://xmlns.jcp.org/jsf/composite">
<cc:interface>
<cc:attribute name="value" type="java.lang.String" default=""/>
<cc:attribute name="label" type="java.lang.String" default=""/>
</cc:interface>
<cc:implementation>
<option value="#{cc.attrs.value}" label="#{cc.attrs.label}"/>
</cc:implementation>
</html>
With this approach I can create something like this
<myTag:dataList id="test">
<myTag:option value="1" label="label1"/>
<myTag:option value="2" label="label2"/>
<myTag:option value="3" label="label3"/>
</myTag:dataList>
But I need something that allows me have a dynamic list of options. I expect to write the following code(or similar)
<myTag:dataList id="test">
<myTag:options value="#{myBean.myCollection}" var="mySingleObj" itemValue="mySingleObj.value" itemLabel="mySingleObj.label"/>
</myTag:dataList>
You can use <ui:repeat>
to iterate over a collection, here's a basic example.
<ui:repeat value="#{bean.options}" var="option">
<option value="#{option.value}">#{option.label}</option>
</ui:repeat>
Only declaring its var
in a composite gets tricky because a value expression is disallowed in var
attribute. So you cannot do something like var="#{cc.attrs.var}"
. For that, you'd need to create a backing component, bind the <ui:repeat>
to it and during postAddToView
event manually evaluate the var
attribute and set it on the component.
<cc:interface componentType="optionsComposite">
<cc:attribute name="value" />
<cc:attribute name="var" />
<cc:attribute name="itemValue" />
<cc:attribute name="itemLabel" />
</cc:interface>
<cc:implementation>
<f:event type="postAddToView" listener="#{cc.init}" />
<ui:repeat binding="#{cc.repeat}" value="#{cc.attrs.value}">
<option value="#{cc.attrs.itemValue}">#{cc.attrs.itemLabel}</option>
</ui:repeat>
</cc:implementation>
Note the componentType
attribute of <cc:interface>
. It must refer the @FacesComponent
value.
@FacesComponent("optionsComposite")
public class OptionsComposite extends UINamingContainer {
private UIComponent repeat;
public void init() {
repeat.getAttributes().put("var", getAttributes().get("var"));
}
public UIComponent getRepeat() {
return repeat;
}
public void setRepeat(UIComponent repeat) {
this.repeat = repeat;
}
}
Now you can use it the same way as <f:selectItems>
.
<myTag:dataList id="test">
<myTag:options value="#{myBean.myCollection}" var="mySingleObj" itemValue="#{mySingleObj.value}" itemLabel="#{mySingleObj.label}" />
</myTag:dataList>